Skip to content

Instantly share code, notes, and snippets.

@jorgemarsal
Last active August 29, 2015 14:15
Show Gist options
  • Save jorgemarsal/bb880745ada2a5a9b5d2 to your computer and use it in GitHub Desktop.
Save jorgemarsal/bb880745ada2a5a9b5d2 to your computer and use it in GitHub Desktop.

The issue

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.

Possible fix

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.

Conclusion

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment