muppet wrote:

>On Oct 1, 2004, at 4:50 AM, Steve Hay wrote:
>
>  
>
>>Why does the following XS code leak?
>>    
>>
>...
>  
>
>>The Safefree(foo) is commented out in FooFree() because I believe that
>>sv_usepvn() has reallo()'ed foo and will free() it for me when sv's
>>refcount becomes 0.
>>    
>>
>
>according to the docs for sv_usepvn(), that sounds right.  however, 
>it's very mind-bending and obfuscated.  you're transferring the 
>ownership of the memory to the SV, but still cleaning it up what it 
>points to yourself.  i can't help but ask "why?"
>
I'm not cleaning up what it points to.  As I said, the Safefree(foo) was 
deliberately commented-out.  I'm cleaning up foo->buf because that was 
separately allocated and hasn't been "taken over" by the SV.

>
>
>by the way, if sv_usepvn() actually reallocates the pointer you passed 
>to it, then calling FooFree(foo) is going to be very, very bad.
>
Why?  Calling Safefree(foo) is certainly very, very bad, which is why I 
wasn't doing it.  Trying it to see if it made any difference was just an 
act of desperation.  I'm quite relieved that it didn't fix anything.

>
>i added a couple of printfs to the code to see the actual pointer 
>addresses;
>
>void
>foo()
>PPCODE:
>{
>   SV *sv;
>   Foo *foo;
>   sv = NEWSV(0, 0);
>   foo = FooAlloc(aTHX);
>   printf (" -- foo %p\n", foo);
>   sv_usepvn(sv, (char *)foo, sizeof *foo);
>   printf ("     pv %p\n", SvPV (sv, PL_na));
>   SvPOK_only(sv);
>   SvREADONLY_on(sv);
>   FooFree(aTHX_ foo);
>   SvREFCNT_dec(sv);
>}
>
>it looks like on my system the pointer is not getting realloc'd, and i 
>can't see a leak in the output of top (only a 4-byte increase in RSS 
>after 10000 reps).   when i uncomment just the Safefree() in FooFree() 
>i get double-free warnings, so the SV is indeed freeing the memory 
>itself.
>
On my system (WinXP) the pointer is moved.  MS docs for realloc() say 
that it might move the pointer, but it might not.  Linking against the 
debug CRT apparently uses a different realloc() which guarantees to 
always move the pointer.  Don't know if you have such an option on your 
system?

Presumably you didn't see the leak because your memory wasn't moved.

All this got me thinking some more, though, and I believe I've now 
answered my own question.  FooFree(aTHX_ foo) is wrong because foo is 
still pointing to the space that was originally allocated.  But the 
sv_usepvn() call has (in my case) moved the allocated memory block, so 
that original location is now toast.  foo->buf (whatever that means now) 
is no longer necesarily pointing to where the 1024 char's were put [in 
fact, printing foo->buf before and after the sv_usepvn(), I see that it 
is not!], so Safefree(foo->buf) doesn't free those char's.

What I need to do to fix it is retrieve the address of the (moved) Foo 
structure and FooFree() that.  This doesn't leak:

void
foo()
PPCODE:
{
  SV *sv;
  Foo *foo;
  sv = NEWSV(0, 0);
  foo = FooAlloc(aTHX);
  sv_usepvn(sv, (char *)foo, sizeof *foo);
  SvPOK_only(sv);
  SvREADONLY_on(sv);
  FooFree(aTHX_ (Foo *)SvPVX(sv));
  SvREFCNT_dec(sv);
}

- Steve



------------------------------------------------
Radan Computational Ltd.

The information contained in this message and any files transmitted with it are 
confidential and intended for the addressee(s) only.  If you have received this 
message in error or there are any problems, please notify the sender immediately.  The 
unauthorized use, disclosure, copying or alteration of this message is strictly 
forbidden.  Note that any views or opinions presented in this email are solely those 
of the author and do not necessarily represent those of Radan Computational Ltd.  The 
recipient(s) of this message should check it and any attached files for viruses: Radan 
Computational will accept no liability for any damage caused by any virus transmitted 
by this email.

Reply via email to