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

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?

  • Comment on Re^5: semi-panic: attempt to dup freed string?

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

    I'm looking to share a blessed reference to any arbitrary lump of memory--the struct in this example.

    Skipping the intermediate SV, ie. RV->struct rather than RV->SvUV->struct seemed like a good idea as it avoided the subject error, but it doesn't work because when the RV is cloned, Perl assumes it's value is a SV* and clones that "SV" also, which screws things completely.

    Using RV->SvUV->struct recreates the original problem.

    I think that I should be able to prevent the SvUV being destroyed prematurely by having it's refcount incremented by the cloning process and decremented by the DESTROY method. The problem is that the CLONE method is called as a class method, not an instance method making it impossible to take full control of the cloning method.

    I don;t currently see a way around this?


    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 looking to share a blessed reference to any arbitrary lump of memory--the struct in this example.

      That's not very clear. There is no shared reference, and the blessed scalar contains a string, not a reference.

      SV = IV(0x982f560) at 0x982f564 REFCNT = 1 FLAGS = (PADMY,ROK) RV = 0x9814874 SV = PVMG(0x9863320) at 0x9814874 REFCNT = 2 FLAGS = (OBJECT,POK,READONLY,pPOK) IV = 0 NV = 0 PV = 0x982a504 "T&\316\t"\0 CUR = 4 LEN = 8 STASH = 0x982f534 "O"

      I'm going to assume you meant "I'm looking to share an arbitrary lump of memory--the struct in this example."

      You already succeeded in doing that. «o» in both threads and thus «*o» is the same too.

      int set( SV *rv, SV *in ) { O *o = *(O**)SvPV( SvRV( rv ), PL_na ); o->sv = newSVsv( in ); printf( "S:rv;%p o:%p o->sv:%p\n", rv, o, o->sv ); return 1; } SV *get( SV *rv ) { O *o = *(O**)SvPV( SvRV( rv ), PL_na ); printf( "G:rv;%p o:%p o->sv:%p\n", rv, o, o->sv ); return newSVsv( o->sv ); } S:rv;0x8d1c9f4 o:0x87736f4 o->sv:0x8d1d374 G:rv;0x8641564 o:0x87736f4 o->sv:0x8d1d374

      The problem isn't with sharing an arbitrary lump of memory. The problem is you're trying to share something you don't own and gets destroyed by the owner (the thread's Perl interpreter) when it exits.

      I think that I should be able to prevent the SvUV being destroyed prematurely by having it's refcount incremented

      Reference counts don't matter in global destruction. Well, it might affect the order in which scalars get destroyed, but it won't prevent it from getting destroyed.

      If you were to create the SV in the receiver, then it would work.

      Update: Minor touch-ups for clarity.

      Since you cannot change the ownership of an SV from one interpreter to another, this creates the SV in the receiver.

      #! perl -slw use strict; package O; #use Inline qw( FORCE NOISY NOCLEAN ); use Inline C => <<'END_C', NAME => 'xso'; 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 = newSVuv( (UV)o ); SV *rv = newRV( oh ); o->sv = newSV(0); sv_bless( rv, gv_stashpv( package, 0 ) ); SvREADONLY_on( oh ); SvREADONLY_on( rv ); printf( "Creating oh:%p o:%p o->sv:%p\n", oh, o, o->sv ); return rv; } int set( SV *rv, SV *in ) { SV *oh = SvRV( rv ); O *o = (O*)SvUV( oh ); sv_setsv( o->sv, in ); printf( "Setting oh:%p o:%p o->sv:%p\n", oh, o, o->sv ); return 1; } SV *get( SV *rv ) { SV *oh = SvRV( rv ); O *o = (O*)SvUV( oh ); printf( "Getting from oh:%p o:%p o->sv:%p\n", oh, o, o->sv ); return newSVsv( o->sv ); } void DESTROY( SV *rv ) { SV *oh = SvRV( rv ); O *o = (O*)SvUV( oh ); printf( "Destroying oh:%p o:%p o->sv:%p\n", oh, o, o->sv ); /* TODO: We can only destroy oh and o in the original. SvREFCNT_dec( o->sv ); free(o); */ } END_C package main; use threads; use Devel::Peek; my $o = O->new(); $o->set( "abcde" ); print $o->get(); print "\nthreaded\n"; async { $o->set( "12345" ); }->join; #<>; print $o->get(); #<>;

        Okay. Ignore the previous reply. The penny has dropped.

        I can't store a reference to an SV allocated by perl inside my struct, because when a thread ends, the referenced SV will be GC'd and I'll end up holding a reference to a freed scalar.

        Your fix is to allocate an SV yourself, and assign a reference to it into the struct. And the set() copies teh contents of the inbound SV, not assign a reference to it.

        The code in the DESTROY() method is there to clean up the SV you allocated, but the TODO is because you haven't found, (or have, but haven't yet implemented), a mechanism to decide when to free the struct and it's contents. I think I see a way to do that.

        I think this gives me what I need. For that, and your time, I thank you.


        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.
        this creates the SV in the receiver.

        Sorry, but could you point out which piece(s) of code are doing that? And what you mean by "in the reciever"?

        Also, is the code in the DESTROY method doing anything useful?


        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.

      The problem is that the CLONE method is called as a class method,

      I think you have to use magic.