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.