On Apr 20, 2010, at 10:12 AM, Simon Urbanek wrote: > > On Apr 19, 2010, at 1:22 PM, Seth Falcon 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). >> > > Can you elaborate on that? (It's really tricky to test this since you cannot > attach a finalizer to the allocated memory). > > AFAICT the R_alloc allocates a regular R vector (raw or real depending on > size) so the usual R object rules apply. Then it is attached to the VStack. > If you also assign it to any other object accessible from the GC roots > (before the VStack goes away) then even removing the VStack entry won't cause > de-allocation because it will be flagged from the other root at mark time so > it won't be garbage collected. VStack is not released blindly it is simply > pruned and left to garbage collection to decide whether to release the > objects or not. >
Ah, I now see the issue - I missed the part that you're NOT using it as SEXP (tag/prot) in the EXTPTR but as void pointer in which case it is not traversed at GC time - point taken. If you assign it as SEXP anywhere (list, vector, etc.) then my point remains ;). But, again, use PROTECT(allocVector(RAWSXP, ..)) for the same yet safe effect. Cheers, Simon > That said, the lesson to Melissa is that you can simply allocate a raw vector > with the same effect - there is no need to use R_alloc() in her case (is user > code PROTECTing is sort of equivalent to the VStack used internally). > > Cheers, > Simon > > > >> 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@r-project.org mailing list >> https://stat.ethz.ch/mailman/listinfo/r-devel >> >> > > ______________________________________________ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel > > ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel