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.