in reply to Re: semi-panic: attempt to dup freed string?
in thread semi-panic: attempt to dup freed string?

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.

Replies are listed 'Best First'.
Re^3: semi-panic: attempt to dup freed string?
by ikegami (Patriarch) on Mar 24, 2011 at 21:36 UTC

    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.

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

      Nice hypothesis!++

      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.

      Indeed. Or, as RVs and IVs are now aliases for the same thing, skip the intermediary completely, which appears to fix the problems Update: No it doesn't. I was so happy to see the back of the panic, that I missed that the contained value is updated by the thread :(

      #! 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 *rv = newRV( o ); o->sv = mem( sizeof( SV* ) ); sv_bless( rv, gv_stashpv( package, 0 ) ); SvREADONLY_on( rv ); printf( "N:rv:%p o:%p\n", rv, o ); return rv; } int set( SV *rv, SV *in ) { O *o = *(O**)SvRV( rv ); printf( "S:rv;%p o:%p\n", rv, o ); o->sv = newSVsv( in ); return 1; } SV *get( SV *rv ) { O *o = *(O**)SvRV( rv ); SV *old = newSVsv( o->sv ); SvREFCNT_inc( old ); printf( "G:rv;%p o:%p old:%p\n", rv, o, old ); return old; } 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:000000000025E128 o:00000000040D6738 O=SCALAR(0x40d6738) S:rv;000000000025E248 o:0000000003CB6088 G:rv;000000000025E248 o:0000000003CB6088 old:00000000002B7980 abcde threaded CLONE:O S:rv;0000000004361010 o:000000000432F5F8 DESTROY:O=SCALAR(0x4361028) G:rv;000000000025E248 o:0000000003CB6088 old:00000000002B79E0 abcde DESTROY:O=SCALAR(0x40d6738)

      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.

        I'm guessing you're trying to avoid the overhead of :shared magic? Are you trying to share scalar between two threads or just transfer a scalar from one thread to another? Does it have to be a scalar, or can it just be a string?

      By the way, using a string buffer to store a pointer is a waste. An IV is guaranteed to be big enough.

      I think the reason people place pointers into the string buffer of the PV is to circumvent perl's overzealous CLONEing code from messing with it.

      If you try RV->pointer_to_non_SV, you cannot bless the RV because perl check what is pointed at.

      If you try RV->SvUV->pointer_to_nonSV, you can bless the Rv, but when CLONE gets it hands on it, it not only clones the RV and the SvUV, but because the SvUVs are aliased for SvRVs, it also assumes that the value in the SvUV is an SV* and clones that also. At least that is what seems to happen?

      By going the RV->SvPV->string(containing pointer_to_non_SV), CLONE does expect the string to contain a pointer and so copies the original string value verbatim.

      It is a messy roundabout route, but I don't see a viable alternative? And even that doesn't seem to work properly.

      Grr. Why is none of this shit documented? Where are the people that know how this stuff works?


      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.

        but because the SvUVs are aliased for SvRVs, it also assumes that the value in the SvUV is an SV* and clones that also.

        If Perl assume all UVs were really pointers to SVs, it would crash left and right. Either the scalar is a reference (ROK) or a UV (IOK + IsUV). What you describe will only happen for the former. I didn't suggest using a reference.