in reply to Re: panic: memory wrap
in thread panic: memory wrap

I managed to reproduce the problem in a standalone testcase.

It seems that the different coderef values from Perl and XS are a red herring. I guess dereferencing a coderef in Perl has some indirection magic that I don't understand, because I get different values in the following test script, but that doesn't stop it from working?

#! perl -slw use strict; use Inline 'NoClean', 'FORCE', 'INFO' ; use Inline Config => WARNINGS => 4; use Inline 'C' => 'DATA', NAME =>'test'; sub recorder{ print "record: @_"; } sub player{ print "player: @_"; } printf "r:%x p:%x\n", \&recorder, \&player; setCallbacks( \&recorder, \&player ); record( 'test' ); #record( 'test' ); #play( 'test' ); __DATA__ __C__ SV *g_rec = 0, *g_play = 0; int setCallbacks( SV *rec, SV *play ) { printf( "r:%x p:%x\n", rec, play ); g_rec = rec; SvREFCNT_inc( g_rec ); g_play = play; SvREFCNT_inc( g_play ); return 0; } int record( SV *m ) { call_sv( g_rec, G_VOID ); return 0; } int play( SV *m ) { call_sv( g_play, G_VOID ); return 0; }

As is, with the second call to record() and that to play() commented out, the program runs fine

P:\test>test r:226004 p:2260b8 r:19499e4 p:2252a8 record: test

Different addresses(?), but it works. Remove either comment and it panics.

P:\test>test r:226004 p:2260b8 r:19499e4 p:2252a8 record: test panic: memory wrap at P:\test\test.pl line 16.

I assume that it is something to do with my (lack of) handling of the stack(?), but I've tried various combinations of the Inline_* macros without success.

Cluebats gratefully receieved.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"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: panic: memory wrap
by dave_the_m (Monsignor) on Nov 14, 2005 at 09:55 UTC
    The \ operator creates a temporary reference, which is usually freed at the end of the current statement. You're saving that tmp ref. Instead, just store the the thing pointed by the ref, ie the CV.

    Dave.

      Um, thanks, but could you give that cluebat a slightly heavier heft, and maybe go for the head-on strike rather than a glancing blow?

      The \ operator creates a temporary reference, which is usually freed at the end of the current statement.

      Obviously I cannot omit the \, as I would be calling the function rather than getting a reference to it.

      As far as I can tell, that means you are suggesting that I dereference the value I pass from the Perl code, once I get my hands on it inside the XS code?

      Part of the problem is that I am not at all sure what it is I am receiving inside the XS code?

      Dumping the (temporary) SV that I get from using \&sub using Devel::Peek, I see this:

      SV = RV(0x1840114) at 0x194968c <<<<<<<<<< This is the value I receive + in the XS code. REFCNT = 1 FLAGS = (TEMP,ROK) RV = 0x226004 <<<<<<<<<<<<<<<<<<<<<<<< This is the value I see in +the Perl code SV = PVCV(0x1824094) at 0x226004 REFCNT = 2 FLAGS = () IV = 0 NV = 0 COMP_STASH = 0x2251d0 "main" START = 0x19588d4 ===> 11609 ROOT = 0x1958890 XSUB = 0x0 XSUBANY = 0 GVGV::GV = 0x1959798 "main" :: "recorder" FILE = "P:\test\test.pl" DEPTH = 0 FLAGS = 0x0 OUTSIDE_SEQ = 951 PADLIST = 0x226010 PADNAME = 0x22601c(0x1826a5c) PAD = 0x22604c(0x182ebb4) OUTSIDE = 0x2253c8 (MAIN) r:226004 <<<<<<<<< Printed from Perl r:194968c <<<<<<<<< Printed from XS

      Looking at perlcall there are 4 ways to invoke a sub, but only one of them, call_sv() uses a reference rather than a string that will need to be resolved every time.

      I'm using this, successfully, once.

      You're saving that tmp ref. Instead, just store the the thing pointed by the ref, ie the CV.

      From that, I take it that I should in some way be dereferenceing, or extracting something from the value I receive within the XS code, but looking at perlapi and perlcall, the only macro that seems to do anything related is

      sv_2cv Using various gambits, try to get a CV from an SV; in addition, try if + possible to set *st and *gvp to the stash and GV associated with it. + CV* sv_2cv(SV* sv, HV** st, GV** gvp, I32 lref)

      Which also takes an HV** and a GV**, gives no information on what I would do with those, or how I would invoke a CV* once had it?

      I also (previously) ran across the section of perlcall that starts with

      You should note that if it is necessary to store the SV (name in the example above) which corresponds to the Perl subroutine so that it can be used later in the program, it not enough just to store a copy of the pointer to the SV. Say the code above had been like this

      and attempted to follow the directions for saving a copy of the SV:

      #! perl -slw use strict; use Inline 'NoClean', 'FORCE', 'INFO' ; use Inline Config => WARNINGS => 4; use Inline 'C' => 'DATA', NAME =>'test'; use Devel::Peek; sub recorder{ print "record: @_"; } sub player{ print "player: @_"; } print Dump \&recorder; printf "r:%x p:%x\n", \&recorder, \&player; setCallbacks( \&recorder, \&player ); #record( 'test' ); play( 'test' ); __DATA__ __C__ SV *g_rec = (SV*)NULL; SV *g_play = (SV*)NULL; int setCallbacks( SV *rec, SV *play ) { printf( "r:%x p:%x\n", rec, play ); g_rec = newSVsv( rec ); // updated. // SvREFCNT_inc( g_rec ); g_play = newSVsv( play ); // updated // SvREFCNT_inc( g_play ); return 0; } int record( SV *m ) { call_sv( g_rec, G_VOID ); return 0; } int play( SV *m ) { call_sv( g_play, G_VOID ); return 0; }

      But this code segfaults the first time I call it (which seems like a retrograde step)! With or without my incrementing the refcount?

      Update: Switched from svSetSV() to newSVsv(). This now works the first time and "panic: memory wrap"s the second and subsequent times. Full circle.

      Further cluebats requested.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        I was thinking of something along the lines of:
        int setCallbacks( SV *rec, SV *play ) { g_rec = SvREFCNT_inc(SvRV(rec)); g_play = SvREFCNT_inc(SvRV(play)); return 0; }
        ie store a direct pointer to the CV rather than a pointer to a temporary RV that points to the CV. Note that call_sv() can take a CV as an arg.

        If setCallbacks() can be called more than once then you'll want to initialize the the pointers to Null, then on each call to setCallbacks(), SvREFCNT_dec() the existing g_rec and g_play if they're non-null.

        Dave