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

I'm creating an OO module in XS and have encountered a problem when one of the parameters is an array reference. If the function is passed a reference is to a named array (\@array) it works, but when passed a reference to an anonymous array ([@array\), it mysteriously fails. When I run this test:
my @array = '1' .. '3'; my $test = Test->new([@array]) : print "Ref: ", ref $g->avref, "\n"; use Devel::Peek; Dump($g->avref);
I get the following:
SvTYPE: 10 Ref: REF Attempt to free unreferenced scalar: SV 0x1801464, Perl interpreter: 0 +x1800400 at a line 16. SV = RV(0x1811aa4) at 0x180147c REFCNT = 1 FLAGS = (TEMP,ROK) RV = 0x1801464 SV = PV(0x1801684) at 0x1801464 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x301f90 "(0x1811aa4) at 0x180147c\n REFCNT = 1\n FLAGS = ( +TEMP,ROK)"\0 CUR = 58 LEN = 59
Whereas when I replace \@array for [@array] I get the expected:
SvTYPE: 10 Ref: ARRAY SV = RV(0x1811aa4) at 0x1801464 REFCNT = 1 FLAGS = (TEMP,ROK) RV = 0x180c2c0 SV = PVAV(0x180283c) at 0x180c2c0 REFCNT = 2 FLAGS = (PADBUSY,PADMY) IV = 0 NV = 0 ARRAY = 0x327a10 FILL = 2 MAX = 3 ARYLEN = 0x0 FLAGS = (REAL) Elt No. 0 SV = IV(0x1826870) at 0x1801380 REFCNT = 1 FLAGS = (IOK,pIOK) IV = 1 Elt No. 1 SV = IV(0x1826874) at 0x1801434 REFCNT = 1 FLAGS = (IOK,pIOK) IV = 2 Elt No. 2 SV = IV(0x1826878) at 0x180144c REFCNT = 1 FLAGS = (IOK,pIOK) IV = 3
I've read perlxs, perguts, perlapi, "Extending and Embedding Perl" and googled my brains out, but can't find anything relevant. This is the contents of Test.xs:
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" typedef struct { AV *avref; } test_t; typedef test_t *Test; MODULE = Test PACKAGE = Test Test new (char *class, SV *avref) PROTOTYPE: $\@ CODE: { IV i; test_t *self; New(0, self, 1, test_t); printf("SvTYPE: %d\n", SvTYPE(SvRV(avref))); self->avref = (AV*)SvRV(avref); RETVAL = self; } OUTPUT: RETVAL AV * avref (Test self, AV *avref=Nullav) PROTOTYPE: $;\@ CODE: { if (items == 2) self->avref = avref; RETVAL = self->avref; } OUTPUT: RETVAL
and the typemap is: Test T_PTROBJ

Replies are listed 'Best First'.
Re: Help with XS and anonymous arrays
by rafl (Friar) on Mar 28, 2006 at 23:22 UTC

    Either make a copy of the array that was passed to new or simply increase its reference count. Otherwise perl tries to free it, as you see. That doesn't happen if you pass a named reference because the array is still in the same scope and won't get destroyed therefor.

    For example it should also work with with an anonymous reference if you store it in another lexical variable:

    my @array = 1 .. 3; my $ref = [@array] Test->new($ref);

    Cheers, Flo

      Thanks! That did the trick. I added:
      if (SvREFCNT(avref) == 0) SvREFCNT_inc(avref);

        That's wrong as well. Don't conditionally increment the reference count. Incement it when you create a new reference to it and decrement it when you're not referencing to it anymore.

        Cheers, Flo