In some compiler versions (e.g. GCC 4.6.4 in Ubuntu) when compiling with -rdynamic
two functions with the same name (e.g. dataptr
defined both in routines.h
and barrier.cpp
) are placed in the dynamic symbol table. Subsequently When we do R_GetCCallable("Rcpp", "dataptr")
we get the wrong function at runtime.
When Rcpp registers dataptr
it means this function (in barrier.cpp
):
// [[Rcpp::register]]
void* dataptr(SEXP x){
return DATAPTR(x);
}
However at runtime we're getting this other one (in routines.h
):
inline void* dataptr(SEXP x){
typedef void* (*Fun)(SEXP) ;
static Fun fun = GET_CALLABLE("dataptr") ;
return fun(x) ;
}
This results in infinite recursion (because dataptr
in routines.h
is calling itself). The infinite recursion produces either a segfault (stack overflow) or hangs the process when the compiler does tail call optimization and the infinite recursion get transformed into an infinite loop.
To show the issue let’s create a simple test program:
#include <Rcpp.h>
#include <RInside.h>
#include <iostream>
int main() {
RInside R;
int size = 38;
Rcpp::RawVector raw(size);
std::cout << "done" << std::endl;
return 0;
}
Let’s compile:
g++-4.6 -I/data/R-3.1.2/include -I/usr/local/lib/R/site-library/RInside/include/ -I/usr/local/lib/R/site-library/Rcpp/include/ -I/usr/share/R/include/ -O2 -g -rdynamic -o rcpphang-4.6 rcpphang.cpp -lR -lRblas -lRInside -L/usr/local/lib/R/site-library/RInside/lib/ -L/data/R-3.1.2/lib
g++-4.8 -I/data/R-3.1.2/include -I/usr/local/lib/R/site-library/RInside/include/ -I/usr/local/lib/R/site-library/Rcpp/include/ -I/usr/share/R/include/ -O2 -g -rdynamic -o rcpphang-4.8 rcpphang.cpp -lR -lRblas -lRInside -L/usr/local/lib/R/site-library/RInside/lib/ -L/data/R-3.1.2/lib
If we take a look at the symbol tables we can see that Rcpp.so
has the right dataptr
:
$ nm --dynamic /usr/local/lib/R/site-library/Rcpp/libs/Rcpp.so|grep dataptr
000000000003c8e0 T _Z7dataptrP7SEXPREC
However our programs have extra symbols that shouldn't be there. In this case GCC 4.6 is exporting 3 extra symbols for dataptr
and GCC 4.8 is exporting 2 extra symbols:
$ nm --dynamic rcpphang-4.6|grep dataptr
0000000000402b50 W _Z7dataptrP7SEXPREC
0000000000604698 u _ZGVZ7dataptrP7SEXPRECE3fun
00000000006046a0 u _ZZ7dataptrP7SEXPRECE3fun
$ nm --dynamic rcpphang-4.8|grep dataptr
0000000000604688 u _ZGVZ7dataptrP7SEXPRECE3fun
0000000000604680 u _ZZ7dataptrP7SEXPRECE3fun
If we run the programs the one compiled with GCC 4.8 works fine but the one compiled with GCC 4.6 hangs.
One possible workaround is to define the functions in routines.h
with visibility hidden
like this:
inline __attribute__ ((visibility ("hidden"))) void* dataptr(SEXP x){
If we compile again (after adding hidden
) the result is:
nm --dynamic rcpphang-4.8|grep dataptr
<empty>
nm --dynamic rcpphang-4.6|grep dataptr
<empty>
In this case dataptr
is not being exported and if we run the programs both finish sucessfully.
This is a really tricky issue because it only appears when compiling with certain versions (e.g. GCC 4.6.4 in Ubuntu) and certain flags (-rdynamic
).
Although the bug is only triggered under those conditions we believe this is an Rcpp bug and we should fix it there.
We're not the only ones we've seen this:
We're happy to discuss this. Let us know if you need more clarifications or something doesn't make sense. If you're comfortable with the hidden
workaround we can send you a pull request that does this for the 28 exported functions. It only changes routines.h
. We've run R CMD check
with the hidden
fix and everything works fine.