Hi,

I'm using the XS stack macros to call a method that returns a reference to
an array. The way I think I should do it performs correctly but emits
spurious warnings of "Attempt to free unreferenced scalar..." When I try to
eliminate that message by toying with reference counts and mortality I get
burned by either failed attempts and/or memory leaks.

Here's some test code showing my utter confusion:

use strict;
use warnings;

package Mod;

sub new {
    return bless [ 'meh' ], shift;
}
sub foo {
    return [ 0..$_[1]-1 ];
}

package main;

my $m = Mod->new;

for ( 1..10000 ) {
#    my $v = foo($m,30);
    test($m,30);
    print "Iteration: $_\n" unless $_ % 10_000;
}

use Inline C => <<'EOC';

SV* foo(SV* mod,SV* upto) {
    SV* values;
    int count;
    int i;
    dSP;
    PUSHMARK(SP);
    XPUSHs(mod);
    XPUSHs(sv_mortalcopy(upto));
    PUTBACK;
    count = call_method( "Mod::foo", G_SCALAR );
    SPAGAIN;
    if ( count != 1 )
        croak("Mod::foo didn't return a sole value.");
    values = POPs;
    PUTBACK;

    // Horrible, stops the warnings but causes leaks
//    SvREFCNT_inc(values);

    if ( SvTYPE(SvRV(values)) != SVt_PVAV )
        croak("Mod::foo didn't return a reference to an array.");
//    printf("Reference count of [ref,array]:
[%i,%i]\n",SvREFCNT(values),SvREFCNT((SV*)SvRV(values)));
//    return values;
    return sv_2mortal(values);
}

void test(SV* mod,SV* upto) {
    int i;
    SV* values;
//    values = foo(mod,upto);
    values = newSV(0);
    for ( i = 0; i < 10; i++ ) {
        sv_setsv(values,foo(mod,upto));
        //Copying the array to a new reference ups its reference count to 2:
        SvREFCNT_dec((SV*)SvRV(values));    // emits warnings
        if ( SvIV(upto) != (int)(av_len( (AV*)SvRV(values) ))+1)
            croak("Length of array != %i",SvIV(upto));
    }

    for ( i = 0; i < (int)(av_len( (AV*)SvRV(values) )) + 1; i++ ) {
        if ( i != SvIV((SV*)*av_fetch( (AV*)SvRV(values), i, 0 )) )
            croak("Bad value");
    }
//    printf("Ref count of [ref,array]:
[%i,%i]\n",SvREFCNT(values),SvREFCNT((SV*)SvRV(values)));
}

EOC

Thanks very much for any pointers,
Blake

Reply via email to