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

This creates and returns a blessed scalar ref containing an allocation in the PV. Why does it crash when I try to look at the PV? (Or even call length on it?)

#! perl -slw use strict; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'END_C', NAME => 'test', CLEAN_AFTER_BUILD => 0; char *newxz( unsigned __int64 bytes ) { char *p; warn( "Attempting allocate %I64u bytes\n", bytes ); Newxz( p, bytes, char ); if( !p ) croak( "Couldn't allocate %I64u bytes\n", bytes ); return p; } SV* new( const char * classname, SV *bits ) { unsigned __int64 bytes = ( SvUV( bits )+7 ) / 8; unsigned char *vector = newxz( bytes ); SV * obj; SV * obj_ref; obj = newSV( 0 ); SvPOK_only( obj ); SvPV_set( obj, vector ); SvLEN_set( obj, bytes ); obj_ref = newRV_noinc( obj ); sv_bless( obj_ref, gv_stashpv( classname, GV_ADD) ); return obj_ref; } END_C use Devel::Peek; my $v = new( 'fred', eval $ARGV[ 0 ] ); #print length $$v; Dump( $$v );

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
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 start of some sanity?

Replies are listed 'Best First'.
Re: [I::C] Why does it segfault?
by Eliya (Vicar) on Mar 15, 2012 at 03:46 UTC

    When loading the respective core file into gdb, it indicated that the segfault had occurred when calling SvLEN_set():

    $ gdb /usr/local/bin/perl core ... Core was generated by `/usr/local/bin/perl -lw ./959669.pl 128'. Program terminated with signal 11, Segmentation fault. #0 0x00007f8382eb85c5 in new (classname=0x11b1170 "fred", bits=<optim +ized out>) at test.xs:23 23 SvLEN_set( obj, bytes ); (gdb) q

    My guess would be this is because the SV created with nevSV(0) doesn't yet have a LEN field.  Using newSV_type(SVt_PV) instead fixed the issue (AFAICT), i.e.

    ... obj = newSV_type(SVt_PV); SvPOK_only( obj ); SvPV_set( obj, vector ); SvLEN_set( obj, bytes ); SvCUR_set( obj, bytes ); ... __END__ $ ./959669.pl 128 ... SV = PVMG(0x1068f90) at 0xfb8d80 REFCNT = 1 FLAGS = (OBJECT,POK,pPOK) IV = 0 NV = 0 PV = 0x149cfa0 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" CUR = 16 LEN = 16 STASH = 0xfd4f08 "fred"

      Thanks Eliya. Makes sense... Now :)


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      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 start of some sanity?

      My guess would be this is because the SV created with nevSV(0) doesn't yet have a LEN field.

      It doesn't have a body at all.

      Using newSV_type(SVt_PV) instead fixed the issue (AFAICT), i.e.

      Shorter: [ nevermind, that'll copy the vector instead of uisng it. ]

      newSVpvn(vector, bytes)
Re: [I::C] Why does it segfault? (NDEBUG?)
by tye (Sage) on Mar 15, 2012 at 02:58 UTC

    It looks to me like you do nothing to upgrade the bare SV to be of sufficient type to hold a PV. But then assert(SvTYPE(sv) >= SVt_PV); should have fired. But perhaps you are building in an environment that doesn't have assert()s enabled.

    Also, the ref you return on the stack is not mortalized which probably means a memory leak.

    Update: Yep, Eliya's reply confirms my first paragraph.

    - tye        

      you do nothing to upgrade the bare SV to be of sufficient type to hold a PV

      According to the docs:

      newSV

      Creates a new SV. A non-zero len parameter indicates the number of bytes of preallocated string space the SV should have. An extra byte for a trailing NUL is also reserved. (SvPOK is not set for the SV even if string space is allocated.) The reference count for the new SV is set to 1.

      Which kind of implies that it creates a PV-type SV -- given that it offers to preallocate some space to the PV.

      But I guess that it just fails to mention that if you give a zero parameter, not only does it not preallocate the space, it doesn't allocate the PV-type fields either :(

      perhaps you are building in an environment that doesn't have assert()s enabled.

      You're right. I had the session configured for /release instead of /debug.

      the ref you return on the stack is not mortalized

      I believe I::C will take care of that for me.


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      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 start of some sanity?

        Ah. I was reading code not documentation. :)

        SV * Perl_newSV(pTHX_ const STRLEN len) { dVAR; register SV *sv; new_SV(sv); if (len) { sv_upgrade(sv, SVt_PV); SvGROW(sv, len + 1); } return sv; }
        I believe I::C will take care of that for me.

        Indeed. Inline::C-Cookbook makes that clear (though doesn't take the credit):

        In this example the sv_2mortal call gets done under the hood by XS, because we declared the return type to be SV*.

        Thanks.

        - tye        

        Which kind of implies that it creates a PV-type SV

        ...when given "a non-zero len parameter", which doesn't apply to your code. You have a gave a zero len parameter, for which its documentation only says it "Creates a new SV." It creates the most basic of SVs:

        use Inline C => <<'__EOI__'; void testing() { SV* sv = newSV(0); sv_dump(sv); SvREFCNT_dec(sv); } __EOI__ testing();
        SV = NULL(0x0) at 0x8eec248 REFCNT = 1 FLAGS = ()

        This creates a PV:

        newSVpvn("", 0)

        I believe I::C will take care of that for me.

        Yes, though it's actually XS by means of the typemap that does it.