BrowserUk has asked for the wisdom of the Perl Monks concerning the following question:

Cause: The internal newSVsv() routine was called to duplicate a scalar that had previously been marked as free.

What does this error actually mean?

Google turned up:

Cause: The internal newSVsv() routine was called to duplicate a scalar that had previously been marked as free.

But what does "marked free" mean? Is that a euphemism for "who's reference count has dropped to 0"?


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
  • Comment on semi-panic: attempt to dup freed string?

Replies are listed 'Best First'.
Re: semi-panic: attempt to dup freed string?
by davido (Cardinal) on Mar 24, 2011 at 08:28 UTC

    Assuming for a moment that "marked free" does mean "who's reference count has dropped to zero", I'd really like to see how your code triggered the error. This wasn't pure Perl, was it?


    Dave

      This wasn't pure Perl, was it?

      No. It is a convoluted bit of XS code called from a convoluted Perl code, and only happens occasionally. and none-deterministically. Threading is involved.

      I'd really like to see how your code triggered the error.

      Me too. I could post everything but even if you got it to compile--it has windows specific calls--the chances of you being able to reproduce the circumstances are slim to none.

      If I knew what the error message meant, even if it doesn't allow me to fix it directly, it might allow me to produce a repeatable test scenario to demonstrate it.

      Besides which, asking what an error message means doesn't seem like such a bad or obscure thing to ask here?


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
Re: semi-panic: attempt to dup freed string?
by Anonymous Monk on Mar 24, 2011 at 08:29 UTC

      Thanks anonymonk. That allowed me to track down this (which I apparently missed first time?):

      SV * Perl_newSVsv(pTHX_ register SV *const old) { dVAR; register SV *sv; if (!old) return NULL; if (SvTYPE(old) == SVTYPEMASK) { Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL), "semi-panic: attem +pt to dup freed string"); return NULL; } new_SV(sv); /* SV_GMAGIC is the default for sv_setv() SV_NOSTEAL prevents TEMP buffers being, well, stolen, and saves + games with SvTEMP_off and SvTEMP_on round a call to sv_setsv. */ sv_setsv_flags(sv, old, SV_GMAGIC | SV_NOSTEAL); return sv; }

      And also this:

      c:\test\perl-5.13.6>findstr SVTYPEMASK *.h sv.h:#define SVTYPEMASK 0xff sv.h:#define SvTYPE(sv) ((svtype)((sv)->sv_flags & SVTYPEMASK)) sv.h:#define SvIS_FREED(sv) ((sv)->sv_flags == SVTYPEMASK)

      Which tends to suggest that when an SV is freed, it's type is set to 0xff to allow duplicate frees to be detected. Though I haven't found the code where that actually happens.

      Which probably means I need to implement a DESTROY method. And possible a CLONE method.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
Re: semi-panic: attempt to dup freed string?
by ikegami (Patriarch) on Mar 24, 2011 at 15:52 UTC
    use Inline C => <<'__EOI__'; void f() { SV* sv1; SV* sv2; sv1 = newSV(0); SvREFCNT_dec(sv1); sv2 = newSVsv(sv1); /* semi-panic: attempt to dup freed string */ } __EOI__ f();

      Thanks. That's interesting, but not the case for my code which greatly simplified looks like this:

      #! perl -slw use strict; package O; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'END_C', NAME => 'xso', CLEAN_AFTER_BUILD => 0; typedef struct { SV**sv; } O; void *mem( size_t size ) { void *p; Newx( p, size, char ); return p; } SV *new( char *package ) { O *o = (O*)mem( sizeof( O ) ); SV *oh = newSVpv( (char*)&o, sizeof( O* ) ); SV *rv = newRV( oh ); o->sv = mem( sizeof( SV* ) ); sv_bless( rv, gv_stashpv( package, 0 ) ); SvREADONLY_on( oh ); SvREADONLY_on( rv ); printf( "N:rv:%p oh:%p o:%p\n", rv, oh, o ); return rv; } int set( SV *rv, SV *in ) { O *o = *(O**)SvPV( SvRV( rv ), PL_na ); printf( "S:rv;%p o:%p\n", rv, o ); o->sv = newSVsv( in ); return 1; } SV *get( SV *rv ) { O *o = *(O**)SvPV( SvRV( rv ), PL_na ); printf( "G:rv;%p o:%p\n", rv, o ); return newSVsv( o->sv ); } void DESTROY( SV *rv ) { printf( "DESTROY:%s\n", SvPV_nolen( rv ) ); } void CLONE( SV *rv ) { printf( "CLONE:%s\n", SvPV_nolen( rv ) ); } END_C package main; use threads; use Devel::Peek; my $o = O->new(); print $o; $o->set( "abcde" ); print $o->get(); print "\nthreaded\n"; async { $o->set( "12345" ); }->join; <>; print $o->get(); __END__ C:\test>xso N:rv:000000000002E218 oh:000000000002E128 o:00000000040FCA98 O=SCALAR(0x2e128) S:rv;000000000002E248 o:00000000040FCA98 G:rv;000000000002E248 o:00000000040FCA98 abcde threaded CLONE:O S:rv;000000000435D8F0 o:00000000040FCA98 DESTROY:O=SCALAR(0x435d908) G:rv;000000000002E248 o:00000000040FCA98 semi-panic: attempt to dup freed string at C:\test\xso.pl line 72, <> +line 1.

      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        Hypothesis: SVs are owned by the tread in which they were created. When a thread exits, any SVs it owns are freed.

        By the way, using a string buffer to store a pointer is a waste. An IV is guaranteed to be big enough. Or you can use the PV itself (using SvPV_set) if you set LEN to zero.