[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