Skip to content

Commit 04ff57e

Browse files
committed
Make preserve list more robust to bad values
XPtrs are marked as null when restoring, so we need to check for this and we also now check that the option is a pairlist before trying to read its value Fixes #121
1 parent c08374e commit 04ff57e

File tree

2 files changed

+44
-13
lines changed

2 files changed

+44
-13
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# cpp11 (development version)
22

3+
* The preserve list is now more robust to invalid values, such as when the XPtr has no address or if non-xptr's are stored in the option. This fixes errors when reloading packages using cpp11 and RStudio's session restores.
4+
35
# cpp11 0.2.3
46

57
* `r_vector::const_iterator::operator*` is now a const method (#113, @bkietz, @xhochy)

inst/include/cpp11/protect.hpp

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,10 @@ static struct {
223223

224224
PROTECT(obj);
225225

226+
if (TYPEOF(list_) != LISTSXP) {
227+
list_ = get_preserve_list();
228+
}
229+
226230
// Add a new cell that points to the previous end.
227231
SEXP cell = PROTECT(Rf_cons(list_, CDR(list_)));
228232

@@ -289,9 +293,15 @@ static struct {
289293
// `CPP11_UNWIND`, so if an error occurs we will not catch the C++ exception
290294
// that safe emits.
291295
static void set_option(SEXP name, SEXP value) {
292-
SEXP opt = SYMVALUE(Rf_install(".Options"));
296+
static SEXP opt = SYMVALUE(Rf_install(".Options"));
293297
SEXP t = opt;
294298
while (CDR(t) != R_NilValue) {
299+
if (TAG(CDR(t)) == name) {
300+
opt = CDR(t);
301+
SET_TAG(opt, name);
302+
SETCAR(opt, value);
303+
return;
304+
}
295305
t = CDR(t);
296306
}
297307
SETCDR(t, Rf_allocList(1));
@@ -312,25 +322,44 @@ static struct {
312322
// policies.
313323
// We instead store it as an XPtr in the global options, which avoids issues
314324
// both copying and serializing.
315-
static SEXP get_preserve_xptr() {
316-
static SEXP preserve_xptr = R_NilValue;
325+
static SEXP get_preserve_xptr_addr() {
326+
static SEXP preserve_xptr_sym = Rf_install("cpp11_preserve_xptr");
327+
SEXP preserve_xptr = Rf_GetOption1(preserve_xptr_sym);
317328

318-
if (preserve_xptr == R_NilValue) {
319-
SEXP preserve_xptr_sym = Rf_install("cpp11_preserve_xptr");
329+
if (TYPEOF(preserve_xptr) != EXTPTRSXP) {
330+
return R_NilValue;
331+
}
332+
auto addr = R_ExternalPtrAddr(preserve_xptr);
333+
if (addr == nullptr) {
334+
return R_NilValue;
335+
}
336+
return static_cast<SEXP>(addr);
337+
}
338+
339+
static void set_preserve_xptr(SEXP value) {
340+
static SEXP preserve_xptr_sym = Rf_install("cpp11_preserve_xptr");
341+
342+
SEXP xptr = PROTECT(R_MakeExternalPtr(value, R_NilValue, R_NilValue));
343+
set_option(preserve_xptr_sym, xptr);
344+
UNPROTECT(1);
345+
}
320346

321-
preserve_xptr = Rf_GetOption1(preserve_xptr_sym);
347+
static SEXP get_preserve_list() {
348+
static SEXP preserve_list = R_NilValue;
322349

323-
if (preserve_xptr == R_NilValue) {
324-
SEXP preserve_list = Rf_cons(R_NilValue, R_NilValue);
350+
if (TYPEOF(preserve_list) != LISTSXP) {
351+
preserve_list = get_preserve_xptr_addr();
352+
if (TYPEOF(preserve_list) != LISTSXP) {
353+
preserve_list = Rf_cons(R_NilValue, R_NilValue);
325354
R_PreserveObject(preserve_list);
326-
preserve_xptr = R_MakeExternalPtr(preserve_list, R_NilValue, R_NilValue);
327-
set_option(preserve_xptr_sym, preserve_xptr);
355+
set_preserve_xptr(preserve_list);
328356
}
329357
}
330358

331-
return preserve_xptr;
359+
return preserve_list;
332360
}
333361

334-
SEXP list_ = static_cast<SEXP>(R_ExternalPtrAddr(get_preserve_xptr()));
335-
} preserved;
362+
SEXP list_ = get_preserve_list();
363+
} // namespace cpp11
364+
preserved;
336365
} // namespace cpp11

0 commit comments

Comments
 (0)