Repository navigation
module property with a free-function getter and member setter crashes at module load #1519
Description
class_<T>::property() has one overload per getter/setter combination (member function, const member function, or free function taking T*). The overload taking a free-function getter and a member-function setter never returns *this:
Rcpp/inst/include/Rcpp/module/Module_Add_Property.h
Lines 80 to 86 in 2cf7685
| template <typename PROP> | |
| self& property( const char* name_, PROP (*GetMethod)(Class*), void (Class::*SetMethod)(PROP), const char* docstring = 0 ){ | |
| AddProperty( | |
| name_, | |
| new CppProperty_GetPointer_SetMethod<Class,PROP>(GetMethod, SetMethod, docstring) | |
| ) ; | |
| } |
template <typename PROP>
self& property( const char* name_, PROP (*GetMethod)(Class*), void (Class::*SetMethod)(PROP), const char* docstring = 0 ){
AddProperty(
name_,
new CppProperty_GetPointer_SetMethod<Class,PROP>(GetMethod, SetMethod, docstring)
) ;
}Flowing off the end of a non-void function is undefined behavior, and the result is used by the next call in the class_<T> builder chain. With Apple clang the compiler emits a trap instruction there, so any module that uses this overload kills the R session as soon as the module is loaded. The compiler does warn:
inst/include/Rcpp/module/Module_Add_Property.h:86:2: warning: non-void function does not return a value [-Wreturn-type]
but sourceCpp() and package builds don't surface warnings by default. The code dates back to 2010; none of the free-function property() overloads are exercised by the test suite.
Reproducible example
repro.cpp:
#include <Rcpp.h>
using namespace Rcpp;
class Counter {
public:
Counter() : n(0) {}
void set_n(int n_) {
n = n_;
}
int n;
};
// getter as a free function taking the object pointer
int get_n(Counter* c) {
return c->n;
}
RCPP_MODULE(counter_module) {
class_<Counter>("Counter")
.constructor()
// free-function getter + member-function setter
.property("n", &get_n, &Counter::set_n);
}repro.R:
Rcpp::sourceCpp("repro.cpp")
cat("module loaded\n")
counter <- new(Counter)
counter$n <- 5L
print(counter$n)Output with R 4.6.1 (macOS 27, Apple clang 21, Rcpp 1.1.2.6 / current master):
Trace/BPT trap: 5 Rscript repro.R
Rscript exits with code 133 (SIGTRAP) while sourceCpp() loads the module; module loaded is never printed. Other compilers may not trap, but the behavior is still undefined.
I'll follow up with a PR that adds the missing return *this; and adds tests covering every property() overload.
Activity