in reply to Writing to Pointer Values (PV) in XS

First I make pointer values like this

If SvLEN is non-zero, the PV belongs to Perl, and Perl will free it. This could be the cause of the segfault you had. You should set SvLEN to zero.

SV* sv = newSV_type(SVt_PV); SvPV_set(sv, (char*)u_ptr); SvLEN_set(sv, 0); /* So Perl won't free it. */ SvCUR_set(sv, sizeof(Uint32)); SvPOK_on(sv);

That way, if Perl reallocates the PV or if the scalar goes out of scope, it won't free the existing PV first. It's up to you to free surface->pixels.

AV * surfacex_pixel_array ( surface )

Perl functions can't return anything but a list of scalar. Specifically, you can't return an array. You need to return a reference to the array, or you need to flatten the array.

SV * construct_p_matrix ( SDL_Surface *surface ) { ... return newRV_noinc(matrix); }

The problem is in setting the value of this pointer value.

use strict; use warnings; use Inline C => <<'__EOI__'; /* Something Perl shouldn't free */ static char s[4] = "\x11\x11\x11\x11"; SV* fetch() { SV* sv = newSV_type(SVt_PV); SvPV_set(sv, s); SvPOK_on(sv); SvLEN_set(sv, 0); SvCUR_set(sv, 4); return newRV_noinc(sv); } __EOI__ my $ref = fetch(); print(unpack('H*', $$ref), "\n"); $$ref = pack('N', 0x22222222); # Bad: Replaces the $ref = fetch(); # PV instead of print(unpack('H*', $$ref), "\n"); # modifying it. substr($$ref, 0, 4, pack('N', 0x33333333)); # OK $ref = fetch(); print(unpack('H*', $$ref), "\n"); substr($$ref, 0, 4) = pack('N', 0x44444444); # OK $ref = fetch(); print(unpack('H*', $$ref), "\n"); substr($$ref, 0) = pack('N', 0x55555555); # OK $ref = fetch(); print(unpack('H*', $$ref), "\n"); vec($$ref, 0, 32) = 0x66666666; # OK $ref = fetch(); print(unpack('H*', $$ref), "\n");
11111111 11111111 33333333 44444444 55555555 66666666

I'm using a reference because my $sv = f(); would copy the string if I returned the scalar directly. You don't need to place refs in your array since the array acts as the reference. For example, the following should work if the array is setup properly:

vec($surf32_matrix->[0][0], 0, 32) = 0x12345678;

That said, your approach seems very fragile.

Replies are listed 'Best First'.
Re^2: Writing to Pointer Values (PV) in XS
by kthakore (Acolyte) on Jun 24, 2010 at 16:31 UTC

    Hi! So I have news on this implementation.

    I would like to put a note here.

    HUGE SUCCESS!

    You can see this implementation on our repo. The relevant files are the XS and the example script .

    What are the fragile issues that you can see? What more can I do ensure memory handling is done correctly

      You can see this implementation on our repo.

      I'm not going to review your code.

      newSV_type is a new addition to the core. If you want to support older Perls, you'll have to use something else, or include ppport (which isn't hard, and will handle other such problems if any). I chose newSV_type because it doesn't create a string buffer that will end up being freed.

      What are the fragile issues that you can see?

      I was referring to how easy it is to accidentally replace the PV. If it's a private interface between your XS and Perl components, no problem. If it's a public interface, it's a problem.

      What more can I do ensure memory handling is done correctly

      Test your code using valgrind.

Re^2: Writing to Pointer Values (PV) in XS
by kthakore (Acolyte) on Jun 27, 2010 at 02:18 UTC

    Moreover when you do:

    /* Something Perl shouldn't free */ static char s[4] = "\x11\x11\x11\x11"; SV* fetch() { SV* sv = newSV_type(SVt_PV); SvPV_set(sv, s); SvPOK_on(sv); SvLEN_set(sv, 0); SvCUR_set(sv, 4); return newRV_noinc(sv); }

    The Devel::Peek::Dump shows:

    SV = IV(0x8add89c) at 0x8add8a0 REFCNT = 1 FLAGS = (PADMY,ROK) RV = 0x8abf520 SV = PV(0x8abc700) at 0x8abf520 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0xb7d0e06c "\21\21\21\21" CUR = 4 LEN = 0

    However for my set of

    SV * sv = newSV_type(SVt_PV); SvPV_set(sv, surface->pixels); SvPOK_on(sv); SvLEN_set(sv, 0); SvCUR_set(sv, surface->format->BytesPerPixel * surface->w * +surface->h); RETVAL = newRV_noinc(sv);

    The surface Devel::Peek::Dump has different types:

    SV = RV(0x142b330) at 0x142b324 REFCNT = 1 FLAGS = (TEMP,ROK) RV = 0x3e90fc SV = PV(0x1287a9c) at 0x3e90fc REFCNT = 1 FLAGS = (POK,pPOK) PV = 0xcea408 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" CUR = 16 LEN = 0

    Why is the type a RV and not IV?

      What's important is that it's ROK, and it is. The RV type doesn't even exist anymore because it got merged with IV type, so don't worry about it.