---
title: "Unprotecting by Value"
author: "Tomas Kalibera"
date: 2018-12-10
categories: ["Internals", "User-visible Behavior"]
tags: ["parsing", "PROTECT bugs"]
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(collapse = TRUE)
```

In short, `UNPROTECT_PTR` is dangerous and should not be used.  This text
describes why and describes how to replace it, including mset-based
functions that have been introduced as a substitute for situations when
unprotection by value is really needed.  This could be of interest to anyone
who writes native code to interface with the R heap, and definitely to all
who use `UNPROTECT_PTR` in their code.

# Background

R provides several functions to protect pointers to R objects held by local
C variables (typed `SEXP`) from the garbage collector.  As documented in
[Writing R Extensions](https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Garbage-Collection),
there are two structures to hold protected pointers: the pointer
protection stack and the precious list.

The *pointer protection stack* is accessed using `PROTECT`/`UNPROTECT`. 
Pointers are unprotected by being removed from the top of the stack.  One
can also use `PROTECT_WITH_INDEX` and then `REPROTECT` to replace a pointer
defined by its position in the stack, which allows to simplify and speed-up
code that repeatedly updates local variables holding pointers (in such
scenarios, one could in principle still use a sequence of
`PROTECT`/`UNPROTECT` operations, instead).  The pointer protection stack
needs to be managed in-line with the C call stack: after returning from a
function, the stack depth should be the same as when the function was called
(pointer protection balance).  These and other rules are described in
[Writing R
Extensions](https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Garbage-Collection)
and [The danger of PROTECT
errors](https://github.com/kalibera/cran-checks/blob/master/rchk/PROTECT.md),
they are relatively easy follow and check, both visually and by tools (also,
pointer-protection balance is checked to some level at runtime).  The
stack-based protection and unprotection are fast, do not require additional
allocation and are automatically handled during R errors (long jumps): a
long jump recovers the previous stack depth, unprotecting the values that
have been left on the stack by the code executed after the jump was set but
before the jump was executed.

Although such situations are very rare, sometimes achieving pointer
protection balance is difficult, sometimes say package code wishes to keep
some allocated space without returning a pointer to it (hence without making
the caller protect it, when we have global variables pointing to R heap and
for some reason cannot turn them into locals).  This is addressed by the
*precious list*, which is accessed using
`R_PreserveObject`/`R_ReleaseObject`.  It is implement as a linked list (and
yes, `R_PreserveObject` allocates!) and objects are unprotected by value. 
There is no automated unprotection on error, the user is always responsible
for unprotecting objects stored on the precious list.  To achieve that in
case of R errors (long jumps) or in callbacks (e.g.  unloading of a
package), it may be necessary to allocate a dummy object, set up its
finalizer, and let the finalizer release needed objects from the precious
list. `R_PreserveObject` and `R_ReleaseObject` are also much slower than
`PROTECT`/`UNPROTECT`.

The API was still not sufficient for very special applications, applications
which used generated code that allocated memory from the R heap, such as the
R parser generated by `bison`.  The parser code uses a stack of semantic
values, which are pointers to objects on the R heap.  Values are pushed on
the stack by the tokenizer during shift operations, are both pushed and
removed during actions of reduce operations, and are removed on some parse
errors.  R errors (long jumps) can also occur during parsing.  The stack is
local to a parsing function.  The key problem is that the code of the parser
is generated and `bison` cannot be customized enough to ensure insertion of
`PROTECT`/`UNPROTECT` operations.  It would be natural to allocate the
semantic values stack on the R heap, protect it, and  protect semantic
values when held in local variables but not yet on the semantic values
stack, all using `PROTECT`/`UNPROTECT`. But, this is not possible. In
principle, `R_PreserveObject`/`R_ReleaseObject` could be used, but one would
have to handle the errors and, most importantly, the performance overhead
would not be acceptable.

To work around this problem, `UNPROTECT_PTR` has been introduced.  It allows
relatively fast unprotect-by-value operation for semantic values protected
in the pointer protection stack.  When new semantic values are created, they
are immediatelly put on the protection stack using `PROTECT` by the
tokenizer and reduce rules.  The values are unprotected by `UNPROTECT_PTR`
inside the reduce rules, and the pointer protection stack depth is restored
after certain parse errors that did not cause a long jump (one can also
define a `destructor` in `bison` for some tokens and make it call
`UNPROTECT_PTR`, as done in the `Rd` parser in package `tools`). 
`UNPROTECT_PTR` removes the first occurrence of the pointer (starting at
stack top) and squeezes the stack, reducing the stack depth.  Using
`UNPROTECT_PTR` this way causes pointer protection imbalance by design (the
tokenizer and reduce rules are implemented in different functions), which
increases cognitive complexity of the code.  It is, however, faster than the
precious list and uses less memory, when used carefully it works with R long
jumps (automated unprotection), and it may well be that there is not a
better way to do protection in the parser than unprotect-by-value (if we
don't modify the generated parser code).  It has been used for many years in
the parser and, unfortunately, started to be used also outside the parser
where not necessary.

It has been known and [documented](https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Garbage-Collection)
 that combining `UNPROTECT_PTR` with `PROTECT_WITH_INDEX` is dangerous,
because by removing a certain object from the stack by `UNPROTECT_PTR` and
squeezing the stack, the *protect index* may become invalid/unexpected
(objects locations on the stack change).  `REPROTECT` would then replace the
wrong pointer, resulting in a memory leak (the object intended for
unprotection stays protected) and, worse, premature unprotection
(`REPROTECT` would replace an object that still was to be protected).  Code
which uses `UNPROTECT_PTR` is also rather hard to read.

# UNPROTECT_PTR is dangerous

While working on some improvements of the parser I realized that
`UNPROTECT_PTR` is unsafe also in combination with `PROTECT/UNPROTECT`.  The
problem occurs when the same pointer is stored multiple times on the
protection stack.  One can accidentally use `UNPROTECT_PTR` to unprotect the
unintended instance of the object, an instance that was intended to be
unprotected by `UNPROTECT`, instead.  At the point of `UNPROTECT_PTR`,
nothing bad yet happens, but, when one later gets to the `UNPROTECT`, the
wrong object gets unprotected, resulting in a premature unprotection
(protect bug).  Unfortunately, it is quite common particularly in the parser
for the same pointer to be protected multiple times (`R_NilValue`, symbols).

To illustrate this, imagine this sequence of pointers on the stack (3 is
protected last, A and A' are the same pointer, A is intended for
unprotection by value):

``` 1A2A'3 ```

after UNPROTECT_PTR(A), we get

``` 1A23 ```

instead of what the enclosing code expected:

``` 12A'3 ```

The depth is ok, say the code later does `UNPROTECT(1)` intending to
unprotect 3 and actually doing so, so still ok.  But, then it calls
`UNPROTECT(1)` intending to unprotect `A'`, but instead unprotecting 2.  As
a result, `A'` (`A`) will still be kept alive (memory leak, possibly
temporary, so not that bad), but 2 will be prematurely unprotected, causing
a protect bug (and one that may be very hard to debug).

In principle, `R_NilValue` and symbols do not need to be protected at all,
but they are and sometimes it makes the code more readable when the
distinction is not made.  Moreover, any function returning a pointer may
sometimes return a fresh pointer and sometimes a pointer that already exists
(including in the parser, where some list manipulating functions work(ed)
that way). So, this seems to be a real danger. Also, using `UNPROTECT_PTR`
the way as in the parser makes verification of other, purely stack-based
`PROTECT/UNPROTECT` operations, harder, both manually and by tools, because
it is not made explicit which pointers were intended to be unprotected by
`UNPROTECT_PTR` and which by `R_ReleaseObject`.

# Phasing out UNPROTECT_PTR

I have thus removed the use of `UNPROTECT_PTR` from all R base code.  It was
relatively easy in the few cases when used outside the parser, I have just
rewritten the code using stack-based protection functions.  I think in all
cases this actually simplified the code.

For use in the parsers (the R parser and the two parsers from package
`tools`), I've introduced API for value-based unprotection outside the
pointer protection stack.  These functions use a `precious multi-set` to
protect these objects; the multi-set is allocated on the R heap and needs to
be protected by the caller (e.g.  using `PROTECT`).  Consequently, it is
automatically unprotected on the long jump, and hence all pointers protected
in the mset get indirectly unprotected as well.  The current implementation
uses a (vector-) list instead of a pair-list, so is also faster than
`R_PreserveObject`/`R_ReleaseObject`, but this is just an implementation
detail that can change and certainly the unprotection could be made faster
if it turns out to be a bottleneck in practice.  The main benefit is that
these functions use a separate structure for unprotection by value, not
polluting the pointer protection stack.

```
SEXP R_NewPreciousMSet(int initialSize);
void R_PreserveInMSet(SEXP x, SEXP mset);
void R_ReleaseFromMSet(SEXP x, SEXP mset);
void R_ReleaseMSet(SEXP mset, int keepSize);
```

To use this API, one needs first to create a new mset using
`R_NewPreciousMSet` and `PROTECT` it.  The mset is expanded automatically as
needed (`R_PreserveInMSet` may allocate).  Objects are released by value via
`R_ReleaseFromMSet` using the same (naive) algorithm as was used in
`UNPROTECT_PTR`, so there should be no performance hit (in principle, the
operations could be faster as they do not have to deal with objects intended
for stack-based protection).  One does not have to release objects
explicitly, they will all be released when the mset is garbage collected
(e.g.  on a long jump that would unprotect the mset). For performance
reasons, one may however use `R_ReleaseMSet` to clear the mset but keep it
allocated, if the allocated size is not bigger than given number of
elements (this can be used e.g. on errors that are not implemented as long
jumps). As anything in R-devel code base, the API is still subject to
change.

Switching from `UNPROTECT_PTR` to the new API is harder than it may first
seem as one has to identify the `PROTECT` operations that are intended for
unprotection by value (and rewrite the code when some code paths unprotect
the same "variable" in one way and other code paths in another). 

# Choosing the right API

I think for memory protection one should always use `PROTECT`/`UNPROTECT`,
possibly with `PROTECT_WITH_INDEX`/`REPROTECT` in performance critical code. 
`R_PreserveObject`/`R_ReleaseObject` help if we have global variables
holding on to R memory, but global variables should be avoided anyway also
for other reasons, so this should be very rare.  Also, arranging for
unprotection on error is a bit tedious. 
`R_PreserveInMSet`/`R_ReleaseFromMSet` should be used only in `bison`/`yacc`
parsers and `UNPROTECT_PTR` should be phased out from all code.
