运行 消毒剂时 Rcpp 函数的段错误(来自 rhub)

segfault on Rcpp function when running with sanitizers (from rhub)

我正在使用 Rcpp Function 编写一个包,包可以编译,并且 R CMD Check 也可以正常工作。早些时候,包的 cvode 函数的输入是 XPtr,但现在输入可以是 XPtrRRcpp 函数(实现是基于 )。目前,RRcppRcpp::XPtr 中的输入函数在包中工作。

该软件包以前有 clang-UBSAN issues,所以我现在尝试使用 rhub 软件包预先检测它们。在 rhub 包的 运行 check_with_sanitizers() 命令上,我收到以下错误:

eval.c:677:21: runtime error: member access within null pointer of type 'struct SEXPREC'

─   *** caught segfault ***
   address (nil), cause 'memory not mapped'
   Segmentation fault (core dumped)

我已经能够将错误隔离到以下代码段中的 ydot1 = rhs_fun(t, y1); 行,即 commenting/un-commenting 上面的表达式重现了错误。

我的问题是 - 在调用 rhs_fun Function 之前我是否应该执行检查以避免 segmentation fault 错误?

注意 - check_with_valgrind() 不会产生错误。

谢谢!

// struct to use if R or Rcpp function is input as RHS function
struct rhs_func{
  Function rhs_eqn;
};

int rhs_func(realtype t, N_Vector y, N_Vector ydot, void* user_data){

  // convert y to NumericVector y1
  int y_len = NV_LENGTH_S(y);

  NumericVector y1(y_len);    // filled with zeros
  realtype *y_ptr = N_VGetArrayPointer(y);
  for (int i = 0; i < y_len; i++){
    y1[i] = y_ptr[i];
  }

  // convert ydot to NumericVector ydot1
  // int ydot_len = NV_LENGTH_S(ydot);

  NumericVector ydot1(y_len);    // filled with zeros

  // // cast void pointer to pointer to struct and assign rhs to a Function
  struct rhs_func *my_rhs_fun = (struct rhs_func*)user_data;

  if(my_rhs_fun){

    Function rhs_fun = (*my_rhs_fun).rhs_eqn;

    // use the function to calculate value of RHS ----
    // Uncommenting the line below gives runtime error
    // ydot1 = rhs_fun(t, y1);

  }
  else {

    stop("Something went wrong, stopping!");
  }


  // convert NumericVector ydot1 to N_Vector ydot
  realtype *ydot_ptr = N_VGetArrayPointer(ydot);
  for (int i = 0; i<  y_len; i++){
    ydot_ptr[i] = ydot1[i];
  }

  // everything went smoothly
  return(0);
}

更新 - 根据下面的评论,我添加了检查。所以检查成功,但我可以看到 rhs_fun 是 NULL,因为代码转到 stop 消息。

 if(my_rhs_fun){
    Function rhs_fun = (*my_rhs_fun).rhs_eqn;
    // use the function to calculate value of RHS ----
    if (rhs_fun){
      ydot1 = rhs_fun(t, y1);
    }
    else{
      stop("Something went wrong");
    }
  }
  else {
    stop("Something went wrong, stopping!");
  }

添加的检查也被添加到结构中

  if (Rf_isNull(input_function)){

    stop("Something is wrong with input function, stopping!");
  }

检查成功,但我看到 rhs_funNULL,因为打印了 else 消息

   Error in cvode(time_vec, IC, ODE_R, reltol, abstol) : 
     Something went wrong
   Execution halted

不知道为什么,因为我试过的例子没有投诉。

最有可能成为 NULL 参考的候选人是 rhs_fun。因此在执行函数之前进行测试是有意义的:

if(rhs_fun) {
   ...
} else {
   stop(...)
}

R API 函数 Rf_isNull 在这里不合适,因为它检查类型 NILSXPSEXP 和实际 [=16= 的段错误].

此外,我会检查您是否没有在结构中插入 NULL 引用,但我发现那里不太可能出现任何问题。

总的来说,这只是一种解决方法。知道是什么触发了这种行为会很有趣。