【问题标题】:C functions in R packages - Rsession aborted when function endsR包中的C函数-函数结束时Rsession中止
【发布时间】:2020-05-19 16:57:44
【问题描述】:

问题

我正在尝试将旧的 C 代码包装到 R 包中。

到目前为止,我已经设法让 RStudio 编译代码、导出函数,并且函数主体中的所有内容都可以正确执行,直到执行结束。

然后,Rsession 中止并且没有错误消息(除了重启会话按钮)。

我的问题是:为什么?以及如何解决?

编辑:我找到了一种让它工作的方法,它在这篇文章的结尾,但我仍然没有回答这两个问题。

代码位

包装器看起来像这样:

#' @useDynLib mypackage main_
#' @export
cellid <- function(args) {

  # Example input:
  # args <- "cell -p ~/Projects/Colman/HD/scripts/cellMagick/data/images/parameters.txt -b /tmp/Rtmp7fjlFo/file2b401093d715 -f /tmp/Rtmp7fjlFo/file2b402742f6ef -o ~/Projects/Colman/HD/uscope/20200130_screen_act1_yfp/1/Position001/out"

  argv <- strsplit(args, " ")[[1]]  # Split arguments
  argc <- length(argv)  # Get length

  .C(main_, as.integer(argc), as.character(argv))
}

实际功能如下:

int main_(int* aargc, char* argv[]){

  ... DO A LOT OF STUFF ...

  return 1;
}

我尝试过的

正如我之前所说,如果我去寻找函数对预期系统文件的影响,我会在那里找到所有内容。我必须防止 Rsession 崩溃的唯一方法是在返回之前引发错误:

int main_(int* argc, char* argv[]){

  ... DO A LOT OF STUFF ...

  error("everything works up to this point");
  return 1;
}

我尝试了很多东西,很盲目。例如,在函数定义中将 int 更改为 void 并省略 return 语句并没有帮助。

我按照here 的建议使用了 lldb,从中得到以下信息:

Process 7900 stopped
* thread #1, name = 'R', stop reason = signal SIGSEGV: invalid address (fault address: 0x0)
    frame #0: 0x00007ffff7a946f5 libc.so.6`__strlen_avx2 + 21
libc.so.6`__strlen_avx2:
->  0x7ffff7a946f5 <+21>: vpcmpeqb (%rdi), %ymm0, %ymm1
    0x7ffff7a946f9 <+25>: vpmovmskb %ymm1, %eax
    0x7ffff7a946fd <+29>: testl  %eax, %eax
    0x7ffff7a946ff <+31>: jne    0x7ffff7a947f0            ; <+272>

我无法解释,我的 C 技能基本为零。

缩小原因

我只能将问题缩小到 C 函数结束的那部分,而 R 必须继续(我猜)。

也许问题出在指针对象上(argvargc)。我注意到argcargv 在函数执行过程中改变了它们的内容(即它们被缩短了,见下文)。

函数开头:

Input argument number (argc[0]): 9
Input argument (argv[i] for printf): cell -p ~/Projects/Colman/HD/scripts/cellMagick/data/images/parameters.txt -b /tmp/Rtmplr4Q90/file26f12a94a144 -f /tmp/Rtmplr4Q90/file26f175cd02e5 -o ~/Projects/Colman/HD/uscope/20200130_screen_act1_yfp/1/Position001/out

函数结束时:

Input argument number (argc[0]): 1
Input argument (argv[i] for printf): cell

虽然我不确定这是否会成为问题,但这种副作用通常是由 glib 的 g_option_context_parse 解析参数引起的。

对我来说很可疑,在 g_option_context_parse 行之后评论所有内容仍然会导致段错误,但评论该行 之后的所有内容不会导致段错误。

R 是否期望发现 argc 和 argv 不变?如果没有,它会崩溃吗?


不幸的是,这是我自己能够做到的。

我试图让这个问题保持简短,但完整的source of the C program 是可用的(main 定义在cell.c)。

感谢您的帮助。如果有帮助,请告诉我如何改进我的问题。

【问题讨论】:

  • 表示您将 NULL 或未对齐的指针传递给 strlen。检查堆栈是否为 16 字节对齐。
  • 啊,是的。那是你的问题。 vpcmpeqb(一个 x86 指令)可能要求参数是 16 字节对齐的,并且由于您的堆栈未对齐,它可能不起作用。
  • 不幸的是,我相当于我研究所的 IT 部门。
  • 你应该把你的解决方案放在答案而不是评论中。另外,argc 应该是参数,而不是数组,argv[argc] 应该是 NULL

标签: r c crash package rstudio


【解决方案1】:

一个 hacky 解决方案

我发现g_option_context_parse 改变了argv,当打印时它在所有位置显示空值 > 1:

cell (null) (null) (null) (null) (null) (null) (null) (null)

这与 glib 的文档没有冲突。

但是,如果在脚本末尾的打印循环期间,我为数组中的每个位置(即argv[i] = "";)分配了非空内容,则函数完成后 Rsession 不再中止。

尽管这确实“让它工作”,但我真的不知道为什么会发生这种情况,而且我的修复更多的是一个 hack,而不是我喜欢的。

我将通过.C 接受精通 R 和 C 如何交互的人的回答,他们可以解释为什么会发生这种情况以及如何更优雅地防止它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-15
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多