[Rd] protect/unprotect howto in C code
Michael Dondrup
michael.dondrup at cebitec.uni-bielefeld.de
Wed May 17 18:12:09 CEST 2006
Thank you very much, Thomas!
Thanks to the explanation, I think I could almost track down that bug. May I,
just for clarification, ask a further bunch of questions (sorry). From what
you say, did I get it right:
- 'error in unprotect: stack imbalance' is only a warning, it will not cause
termination, unless R is running as an embedded process (I'm working with
RSPerl package in perl here)?
- Forgetting to unprotect a value is harmless, and will only provoke these
warnings?
- If the protect/unprotect is unbalanced within a function call, R will give
the warning/error already at the exit of this specific function?
- If that is the case, what if I want to return a pointer to a value from a
function? Do have to unprotect it anyway, before?
btw: I'm working on FreeBSD, I found an experimental port of valgrind, too.
Thank you very much again!
Michael
On Wednesday 17 May 2006 16:55 Thomas Lumley wrote:
> On Wed, 17 May 2006, Michael Dondrup wrote:
> > Hi,
> >
> > Im currently trying to debug a 'error in unprotect: stack imbalance'
> > problem and I am curious about two basic questions on the use of PROTECT
> > and UNPROTECT, which I could not figure out:
> >
> > - which objects have to be protected, namely, if the code is something
> > like:
> >
> > SEXP fun, e;
> > /* get the expression e ... */
> > fun = eval(e, R_GlobalEnv);
> > /* or like this?: PROTECT(fun = eval(e, R_GlobalEnv)); */
> > PROTECT(fun = VECTOR_ELT(fun, 1));
> > /* do more things with fun ... */
> >
> > does one need to protect the result of a call to 'eval' immediately? And
> > how about R_tryEval?
> > While searching for code examples in the sources, I found both protected
> > evals and fewer non-protected.
>
> The first rule is that any newly created R object needs to be protected
> before the garbage collector runs, and unprotected before exiting the
> function and after the last time the garbage collector runs.
>
> The second rule is that protection applies to the contents of a variable
> (the R object) not to the variable.
>
> The second rule is that protecting an object protects all its elements.
>
> In the example above
> fun = eval(e, R_GlobalEnv);
> may create a new object (it might just return a pointer to an existing
> function) and so probably needs to be protected.
>
> On the other hand
> fun = VECTOR_ELT(fun, 1);
> does not then need protecting. Since fun is protected, its second element
> is also protected.
>
> So
> PROTECT(fun = eval(e, R_GlobalEnv));
> fun = VECTOR_ELT(fun, 1);
> /* do more stuff with fun */
> UNPROTECT(1);
>
> If you don't know exactly which functions might return a new object or
> trigger the garbage collector it is probably safe to assume that anything
> might [this is the advice in 'Writing R Extensiosn']. Unless you are
> getting close to the limits of the pointer protection stack (eg in
> recursive algorithms), you might be safer writing code like
> PROTECT(fun = eval(e, R_GlobalEnv));
> PROTECT(fun = VECTOR_ELT(fun, 1));
> /* do more stuff with fun */
> UNPROTECT(2);
> but I think it is useful to know that the vector accessors and mutators do
> not allocate memory.
>
>
> A stack imbalance is often due to different numbers of PROTECTs on
> different code paths. These are slightly annoying and become more frequent
> if you use more PROTECTs. On the other hand, R does detect them for you.
> If you don't use enough PROTECTs you get bugs that are very hard to track
> down [the best bet is probably valgrind + gctorture() to provoke them into
> showing themselves early, but that's only available on Linux].
>
> -thomas
More information about the R-devel
mailing list