From seth at userprimary.net  Mon Apr 19 19:22:24 2010
From: seth at userprimary.net (Seth Falcon)
Date: Mon, 19 Apr 2010 10:22:24 -0700
Subject: [Rd] transient memory allocation and external pointers
In-Reply-To: <80F422FF-8907-4F2F-9AA3-A40423629C61@r-project.org>
References: <u2z3aa2e7491004190739o1d6bcffbi997ac207d51865e0@mail.gmail.com>
	<80F422FF-8907-4F2F-9AA3-A40423629C61@r-project.org>
Message-ID: <4BCC9150.10700@userprimary.net>

On 4/19/10 8:59 AM, Simon Urbanek wrote:
>
> On Apr 19, 2010, at 10:39 AM, Melissa Jane Hubisz wrote:
>
>> Hello,
>> The Writing R extensions manual section 6.1.1 describes the transient
>> memory allocation function R_alloc, and states that memory allocated
>> by R_alloc is automatically freed after the .C or .Call function is
>> completed.  However, based on my understanding of R's memory handling,
>> as well as some test functions I have written, I suspect that this is
>> not quite accurate.  If the .Call function returns an external pointer
>> to something created with R_alloc, then this object seems to stick
>> around after the .Call function is completed, and is subject to
>> garbage collection once the external pointer object is removed.
>>
>

> Yes, because the regular rules for the lifetime of an R object apply
> since it is in fact an R object. It is subject to garbage collection
> so if you assign it anywhere its lifetime will be tied to that object
> (in your example EXTPTRSXP).

I may be misunderstanding the question, but I think the answer is 
actually that it is *not* safe to put memory allocated via R_alloc into 
the external pointer address of an EXTPTRSXP.

Here's what I think Melissa is doing:

SEXP make_test_xp(SEXP s)
{
     SEXP ans;
     const char *s0 = CHAR(STRING_ELT(s, 0));
     char *buf = (char *)R_alloc(strlen(s0) + 1, sizeof(char));
     memcpy(buf, s0, strlen(s0) + 1);
     ans = R_MakeExternalPtr(buf, R_NilValue, R_NilValue);
     return ans;
}

The memory allocated by R_alloc is "released" at the end of the .Call 
via vmaxset(vmax).  Using R_alloc in this way will lead to memory 
corruption (it does for me when I made a simple test case).

For memory that really is external (not SEXP), then you should instead 
use Calloc and register a finalizer for the external pointer that will 
do any required cleanup and then call Free.

If instead you want to have an externally managed SEXP, you could put it 
in the protected slot of the external pointer, but then you should 
allocate it using standard R allocation functions.



+ seth

-- 
Seth Falcon | @sfalcon | http://userprimary.net/



[Rd] transient memory allocation and external pointers
Seth Falcon