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.
Note: this is more of a comment than a real answer, but can't fit it in the comment field. I have a loosely related question and have been trying to better understand the limitations of parent.env<-
.
In your case, note that the problem is actually related to list2env
, not the function. Consider:
f.1 <- function() NULL
ns.1 <- new.env(parent = .BaseNamespaceEnv)
x.1 <- new.env(parent = as.environment(2))
environment(f.1) <- ns.1
x.1$f.1 <- f.1
parent.env(.GlobalEnv) <- x.1
detach()
Works, but:
x.2 <- list2env(list(a=1), parent=as.environment(2))
parent.env(.GlobalEnv) <- x.2
detach()
crashes. Here, we are not even doing anything complex at all with the environment we're using as a parent, other than it was created with list2env
. Looking at the source I don't see anything obvious as to why list2env
is a problem but $<-
is not since both internally seem to use defineVar
, but clearly there is a lot going on there that I don't understand.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With