The following code reproducibly segfaults when executed in R (3.0.2 but I’m assuming it’s similar for other versions):
ns = new.env(parent = .BaseNamespaceEnv)
local(f <- function () 42, envir = ns)
x = list2env(as.list(ns), parent = as.environment(2))
parent.env(.GlobalEnv) = x
detach()
Yes, I know that the documentation on parent.env
says
The replacement function
parent.env<-
is extremely dangerous as it can be used to destructively change environments in ways that violate assumptions made by the internal C code. It may be removed in the near future.
That’s what I seem to be running into here. However, I would like to understand why this behaviour is the way it is, and how to avoid it.
The following simplified code does not have this problem:
x = new.env(parent = as.environment(2))
local(f <- function () 42, envir = x)
parent.env(.GlobalEnv) = x
detach()
… so it seems that it makes a difference that x
contains a function whose parent.env
is a different (unattached) environment.
Likewise, using attach
instead of parent.env<-
does not lead to a crash. (So why not simply use attach
? Because in my code, the .GlobalEnv
part is a variable which may refer to different environments.)
The crash dump tells me that the segfault happens in do_detach
(envir.c
). The code contains the following lines:
isSpecial = IS_USER_DATABASE(s);
if(isSpecial) {
R_ObjectTable *tb = (R_ObjectTable*) R_ExternalPtrAddr(HASHTAB(s));
if(tb->onDetach) tb->onDetach(tb);
}
I have no idea what IS_USER_DATABASE
does – maybe this is related? Merely adding an .onDetach
method to my environment (.onDetach = function (x) x
) did not help.