[Rd] transient memory allocation and external pointers

Melissa Jane Hubisz mjhubisz at gmail.com
Tue Apr 20 15:24:05 CEST 2010


Thanks for the responses.  Seth's example is indeed what I was trying
(hoping) to do, it seems to work on my system fine (ubuntu x86_64, R
2.10.1).  But if it doesn't work for him, then that definitely answers
my question.  I guess I'll have to go the Calloc/Free route.
Thanks,
Melissa

On Mon, Apr 19, 2010 at 1:22 PM, Seth Falcon <seth at userprimary.net> wrote:
> 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/
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>



More information about the R-devel mailing list