2012-04-08 81 views
4

我有我想在沙箱環境中使用特殊的(虛擬)功能:作用域(功能)的定製環境

disable.system.call <- function(...) { 
    mc <- match.call() 
    if (grepl('system', deparse(mc[[2]]))) 
     stop('NONO') 
    eval(mc, env = .GlobalEnv)   
} 

它確實沒有什麼特別的只是檢查,如果第一個參數已在system字其名稱。這只是一個POC的例子。

我後來做了什麼:我將這個簡單的函數分配給某些basestats函數,以查看評估的表達式是否包含作爲第一個參數的system字。例如:

e <- new.env() 
eval(parse(text = 'model.frame <- disable.system.call'), envir = e) 

這工作很酷,因爲電話沒有system裏面用得好好的,但過濾器的工作原理:

> eval(parse(text = 'model.frame("1 ~ 1")'), envir = e) 
    1 
1 1 
> eval(parse(text = 'model.frame(\'1 ~ system("ls -la")\')'), envir = e) 
Error in model.frame("1 ~ system(\"ls -la\")") : NONO 

它甚至有lm調用它調用model.frame工作的內部發現了一個公式像字符串:

> eval(parse(text = 'lm(\'1 ~ system("ls -la")\')'), envir = e) 
Error in model.frame(formula = "1 ~ system(\"ls -la\")", drop.unused.levels = TRUE) : 
    NONO 

我試圖去一點,並分配一個非常簡單的函數(disable.system.call)至as.formula,其從model.frame調用。不幸的是我沒有走到這一步:

> e <- new.env() 
> eval(parse(text = 'as.formula <- disable.system.call'), envir = e) 
> eval(parse(text = 'as.formula("1 ~ 1")'), envir = e) 
1 ~ 1 
> eval(parse(text = 'as.formula(\'1 ~ system("ls -la")\')'), envir = e) 
Error in as.formula("1 ~ system(\"ls -la\")") : NONO 
> eval(parse(text = 'model.frame(\'1 ~ system("ls -la")\')'), envir = e) 
    1 system("ls -la") 
1 1    0 
> eval(parse(text = 'lm(\'1 ~ system("ls -la")\')'), envir = e) 

Call: 
lm(formula = "1 ~ system(\"ls -la\")") 

Coefficients: 
    (Intercept) system("ls -la") 
      1    NA 

據我所知model.frame呼籲as.formula但這不起作用(你可以從上面的輸出中看到)。我很確定這不是因爲model.frame在自定義環境中調用stats::as.formulalm以上model.frame

任何提示和想法都會非常受歡迎!

回答

3

如果你不想讓人們能夠使用system,覆蓋定義會更容易。

assignInNamespace(
    "system", 
    function(...) stop("system calls are not allowed"), 
    getNamespace("base") 
) 

system("pwd") #throws an error 

我瘋狂猜測在你的使用情況,但你讓用戶通過任意R代碼裏面的一些其他應用程序?在這種情況下,您可能希望編譯自己的R版本,並刪除危險功能或用傻瓜代替危險功能。


當函數被調用時執行自定義代碼的另一種可能性是trace。例如,

trace(system, quote(stop("You have called system"))) #you may also want print = FALSE 
+0

謝謝,這個答案是很方便的太(+1)!事實上,我不想禁止所有的「系統」調用,它只是一個簡單的POC示例,但我確實需要實現沙箱環境。請參閱:http://sandboxr.no-ip.org/無論如何,'assignInNamespace'看起來很有希望,我需要一些時間在復活節後做一些實驗,並且肯定會給出更詳細的反饋。 – daroczig 2012-04-09 09:07:40

+0

不錯的項目。你見過Live-R,它有類似的事情嗎? http://live-analytics.com – 2012-04-09 15:22:28

+0

從來沒有聽說過Live-R,感謝把我的注意力集中在那個整潔的軟件上!我很喜歡類似的東西,但是有特殊的(預期的)觀衆。我們將看到:)無論如何,關於你的回答:因爲'?assignInNamespace'建議不要在包中使用這個特性(就像我想的那樣)並且不允許我啓用/禁用沙箱環境,似乎我有找到另一種停用這些通話的方式。像grep's R來源類似的功能:)我想要做的是在特殊環境中運行調用,除此之外允許任何事情(用於系統端調用)。 – daroczig 2012-04-09 19:17:30

4

雖然你懷疑這是不是這樣,stats:::model.frame.default被調用,而不是環境e的定製版本。 (這當然是你通常期望從打包函數中得到的行爲,在你的第一個例子中看到的奇怪範圍是一個特例,這是由於lm()使用了'非標準評估',這在底部討論我的答案)。

正如我在下面,你可以使用trace()看到其中as.formula()版本獲取調用在你的每一個案件:

disable.system.call <- function(...) { 
    mc <- match.call() 
    if (grepl('system', deparse(mc[[2]]))) 
     stop('NONO') 
    eval(mc, env = .GlobalEnv)   
} 
e <- new.env() 
eval(parse(text = 'as.formula <- disable.system.call'), envir = e) 


# (1) trace custom 'as.formula()' in environment e 
trace(e$as.formula) 


# Calling model.frame() **does not** call the the custom as.formula() 
eval(parse(text = 'model.frame(\'1 ~ system("ls -la")\')'), envir = e) 
# 1 system("ls -la") 
# 1 1    127 

# (2) trace stats:::as.formula() 
trace(stats:::as.formula) 

# Calling model.frame() **does** call stats:::as.formula() 
eval(parse(text = 'model.frame(\'1 ~ system("ls -la")\')'), envir = e) 
# trace: as.formula 
# 1 system("ls -la") 
# 1 1    127 

編輯:FWIW,原因是您的自定義model.frame()在第一個示例中由lm()調用的是lm()採用了有時稱爲「非標準評估」的內容。 (See this pdf欲瞭解更多關於此主題的信息,則可能比您想要的更多)。關鍵是lm()實際上指導model.frame()在呼叫環境中進行評估;在你的情況下,這導致它找到你的函數版本。

之所以lm()使用非標準的評價是,這樣model.frame()可以訪問公式中命名的變量,即使它們在調用環境(而不是僅僅能夠通過data參數來訪問傳遞的變量lm()發現)。如Thomas Lumley在鏈接的pdf中所述:

如果要求公式中的變量需要在數據參數中,則生活將會簡單得多,但是在引入公式時並未做出此要求。

如果你有興趣,這裏有相關線路從lm定義:

mf <- match.call(expand.dots = FALSE) 
... 
mf[[1L]] <- as.name("model.frame") 
mf <- eval(mf, parent.frame()) 
+0

謝謝,你的回答是非常有用的(+1) - 儘管我已經瀏覽了相關的R源代碼(當然,我意識到「model.frame.default」被調用,因爲沒有其他方法 - if我是對的),我只是在某種程度上通過了lm's來源的'eval'調用。這當然會讓事情變得清晰!我只需要找到一個簡單的方法來強制函數使用我的特殊'as.formula'(如@ RichieCotton的awer),或者爲所有出現的'as.formula'等grep R sources。啊,也感謝那個_pdf_! – daroczig 2012-04-09 09:11:41