I am writing a package using Rcpp
Function
, the package compiles, and R CMD Check
also works fine. Earlier, the input to package's cvode
function was an XPtr
, but now the input can be both XPtr
or an R
or Rcpp
function (the implementation was based on a earlier post). Currently, input functions in R
, Rcpp
and Rcpp::XPtr
work in the package.
The package had previously had clang-UBSAN issues, so I am trying to detect them beforehand now using rhub
package. On running check_with_sanitizers()
command from the rhub
package, I am getting the following error:
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)
I have been able to isolate the error to the line ydot1 = rhs_fun(t, y1);
in the following piece of code, i.e., commenting/un-commenting the expression above reproduces the error.
My question is - is there a check I should be performing before calling the rhs_fun
Function
, to avoid the segmentation fault
error?
Note - check_with_valgrind()
produces no error.
Thanks!
// 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);
}
An update - based on the comments below, I have added checks. So the check succeeds, but I can see the rhs_fun
is NULL as the code goes to the stop
message.
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!");
}
An added check is added to the struct also
if (Rf_isNull(input_function)){
stop("Something is wrong with input function, stopping!");
}
The checks succeed, but I see that rhs_fun
is NULL
as the else
message is printed
Error in cvode(time_vec, IC, ODE_R, reltol, abstol) :
Something went wrong
Execution halted
Not sure why, as the examples I have tried have worked without complaints.