这里有一些有点疯狂的事情。
如果您有一些由R函数调用的C代码(作为共享对象),请尝试将以下代码添加到代码中
void warn() {
int i; // just so the function has some work, but you could make it empty to, or do other stuff
}如果你随后在被R函数调用的C代码中的任何地方调用warn(),你会得到一个段错误;
*** caught segfault ***
address 0xa, cause 'memory not mapped'
Traceback:
1: .C("C_function_called_by_R", as.double(L), as.double(G), as.double(T), as.integer(nrow), as.integer(ncolL), as.integer(ncolG), as.integer(ncolT), as.integer(trios), as.integer(seed), as.double(pval), as.double(pval1), as.double(pval2), as.double(pval3), as.double(pval4), as.integer(ntest), as.integer(maxit), as.integer(threads), as.integer(quietly))
2: package_name::R_function(L, G, T, trios)
3: func()
4: system.time(func())
5: doTryCatch(return(expr), name, parentenv, handler)
6: tryCatchOne(expr, names, parentenv, handlers[[1L]])
7: tryCatchList(expr, classes, parentenv, handlers)
8: tryCatch(expr, error = function(e) { call <- conditionCall(e) if (!is.null(call)) { if (identical(call[[1L]], quote(doTryCatch))) call <- sys.call(-4L) dcall <- deparse(call)[1L] prefix <- paste("Error in", dcall, ": ") LONG <- 75L msg <- conditionMessage(e) sm <- strsplit(msg, "\n")[[1L]] w <- 14L + nchar(dcall, type = "w") + nchar(sm[1L], type = "w") if (is.na(w)) w <- 14L + nchar(dcall, type = "b") + nchar(sm[1L], type = "b") if (w > LONG) prefix <- paste(prefix, "\n ", sep = "") } else prefix <- "Error : " msg <- paste(prefix, conditionMessage(e), "\n", sep = "") .Internal(seterrmessage(msg[1L])) if (!silent && identical(getOption("show.error.messages"), TRUE)) { cat(msg, file = stderr()) .Internal(printDeferredWarnings()) } invisible(structure(msg, class = "try-error", condition = e))})
9: try(system.time(func()))
10: .executeTestCase(funcName, envir = sandbox, setUpFunc = .setUp, tearDownFunc = .tearDown)
11: .sourceTestFile(testFile, testSuite$testFuncRegexp)
12: runTestSuite(testSuite)
aborting ...
Segmentation fault (core dumped)
(END)不用说,如果您从C或C++包装器而不是从R函数调用相同的函数,代码运行得很好。如果您重命名warn(),它也可以正常工作。
有什么想法吗?这是受保护的名称/符号吗?有这样的名字列表吗?我在Ubuntu 12.01 (i686-pc-linux-gnu (32位))上使用的是R版本2.14.1。C代码是用GNU的GCC 4.6.3编译的。
发布于 2012-06-22 03:23:38
这似乎是一个相当有趣的问题。这是我的最小示例,在我拥有的test.c文件中
void warn() {}
void my_fun() { warn(); }我编译它,然后运行
$ R CMD SHLIB test.c
$ R -e "dyn.load('test.so'); .C('my_fun')"在我的Linux4.6.3.版本中,R输出是
> dyn.load('test.so'); .C('my_fun')
R: Success
list()其中"R: Success“来自于libc中定义的warn函数(参见man warn,在err.h中定义)。发生的情况是,R理所当然地加载了几个动态库,然后按照指令加载test.so。当调用my_fun时,动态链接器解析warn,但解析规则是全局搜索warn符号,而不仅仅是在test.so中搜索。我真的不知道全局搜索规则是什么,可能是按照.so的打开顺序,但无论如何,解决方案都不是我所期望的。
那该怎么办呢?指定
static void warn() {}在编译时创建.o时强制解析,从而避免该问题。例如,如果在一个文件(uitties.c)中定义了warn,而在另一个文件中定义了my_fun,那么这就不会起作用。在Linux上,dlopen (用于加载共享对象的函数)可以提供一个标志RTLD_DEEPBIND,它可以在全局之前进行本地符号解析,但是(a) R不以这种方式使用dlopen,并且(b)这种方法有several (见第9页)保留。因此,据我所知,最佳实践是在可能的情况下使用static,并仔细命名函数以避免名称冲突。后者并不像看起来那么糟糕,因为R加载包共享对象,这样包符号本身就不会添加到全局名称空间中(请参阅?dyn.load和local参数,还要注意特定于操作系统的警告)。
我很有兴趣听到一个更健壮的“最佳实践”。
https://stackoverflow.com/questions/11143023
复制相似问题