Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting parent.env, followed by `detach`, segfaults

Tags:

r

environment

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.

like image 207
Konrad Rudolph Avatar asked Apr 01 '14 15:04

Konrad Rudolph


1 Answers

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.

like image 132
BrodieG Avatar answered Nov 16 '22 02:11

BrodieG