[Rcpp-devel] Loading a package using Rcpp Modules results in memory corruption

Douglas Bates bates at stat.wisc.edu
Sun Jan 9 19:41:46 CET 2011


On Sun, Jan 9, 2011 at 12:21 PM, Dominick Samperi <djsamperi at gmail.com> wrote:
>
>
> On Sun, Jan 9, 2011 at 1:07 PM, Dirk Eddelbuettel <edd at debian.org> wrote:
>>
>> On 9 January 2011 at 12:12, Dominick Samperi wrote:
>> | Actually, the problem seems to be pretty transparent, and the
>> | solution is the same (see below). This gets you through Evaluator,
>> | but you fail in SlotProxy in the call to "$<-". The fact that these
>> | problems only appear when gctorture() is turned on suggests
>> | that they all of the same explanation: unprotected SEXP's.
>> |
>> | same:
>> | //#define UNSAFE_CODE
>> | #ifdef UNSAFE_CODE
>> |     int error = LOGICAL( Rf_eval( Rf_lang1( Rf_install("errorOccured")
>> ),
>> | RCPP ) )[0];
>> | #else
>> |     SEXP cmd = PROTECT(Rf_lang1( Rf_install("errorOccured")));
>> |     int error = LOGICAL(Rf_eval( cmd, RCPP ))[0];
>> |     UNPROTECT(1);
>> | #endif
>> |     Rprintf("Got error = %d\n", error);
>> |
>>
>> There may be an impedance mismatch going on.  'Writing R Extension' says
>>
>>    4.3.1 Using gctorture
>>    ---------------------
>>
>>    We can help to detect memory problems earlier by running garbage
>>    collection as often as possible.  This is achieved by
>>    `gctorture(TRUE)', which as described on its help page
>>
>>         Provokes garbage collection on (nearly) every memory allocation.
>>         Intended to ferret out memory protection bugs.  Also makes R run
>>         _very_ slowly, unfortunately.
>>
>>    The reference to `memory protection' is to missing C-level calls to
>>    `PROTECT'/`UNPROTECT' (*note Garbage Collection::) which if missing
>>    allow R objects to be garbage-collected when they are still in use.
>>    But it can also help with other memory-related errors.
>>
>>       Normally running under `gctorture(TRUE)' will just produce a crash
>>    earlier in the R program, hopefully close to the actual cause. See the
>>    next section for how to decipher such crashes.
>>
>>       It is possible to run all the examples, tests and vignettes covered
>>    by `R CMD check' under `gctorture(TRUE)' by using the option
>>    `--use-gct'.
>>
>> I do not see this as compatible with the C++ Design principle we use
>> whereby
>> protection / unprotection occurs relative to the end of scope -- and not
>> after every single assignment or allocation.
>
> Thanks, but note that Doug's original report was not about gctorture(). We
> are using this tool to try to fix the memory corruption problems, and this
> tool seems to be pretty helpful for this purpose, even if it might be too
> demanding in some situations.
>
> Dominick
>
>>
>> In other words, gctorture() may well be a fine test for the C API and its
>> PROTECT and UNPROTECT at every step but possibly not quite as much for
>> Rcpp.
>>
>> Dirk
>>
>> PS Here is slight generalization of your examples. Cases 2 and 3 do not
>> bomb,
>> and Case 3 is using almost all Rcpp idioms (but for the final Rf_eval
>> call).
>>
>>
>> -----------------------------------------------------------------------------
>> // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*-
>>
>> #include "Rcpp.h"
>>
>> RcppExport SEXP testfft(SEXP vec, SEXP env, SEXP choiceS) {
>>
>>    int choice = Rcpp::as<int>(choiceS);
>>    SEXP res = R_NilValue;
>>
>>    if (choice == 1) {
>>        Rprintf("In case 1\n");
>>        // may not survive gctorture(), sometimes!
>>        SEXP call = ::Rf_lcons(Rf_install("fft"),
>>                               Rf_cons(vec , R_NilValue));
>>        res = PROTECT(Rf_eval(call, env));
>>        UNPROTECT(1);
>>
>>    } else if (choice == 2) {
>>        Rprintf("In case 2\n");
>>        // always survives gctorture()
>>        SEXP call = PROTECT(::Rf_lcons(Rf_install("fft"),
>>                                       Rf_cons(vec , R_NilValue)));
>>        res = PROTECT(Rf_eval(call, env));
>>        UNPROTECT(2);
>>
>>    } else if (choice == 3) {
>>        Rprintf("In case 3\n");
>>        Rcpp::Function fft("fft");
>>        Rcpp::Environment env_(env);
>>        Rcpp::Language call(fft);
>>        call.push_back(vec);
>>        res = Rf_eval(call, env_);
>>    }
>>    return res;
>> }
>>
>> -----------------------------------------------------------------------------
>>
>> and
>>
>>
>> -----------------------------------------------------------------------------
>> # Tests Rcpp Evaluator code with PROTECTION fix and gctorture ON.
>> # Should get a complex vector of zeros.
>> library(Rcpp)
>> gctorture()
>> dyn.load("testfft.so")
>> for (i in 2:3) {  # bombs on 1 but not 2 or 3
>>    print(.Call('testfft', 1:20, getNamespace("stats"), i) - fft(1:20))
>> }
>> cat("still here\n")
>>
>> -----------------------------------------------------------------------------
>>
>>
>> edd at max:/tmp/samperi-gc$ r -lRcpp -e'Rcpp:::SHLIB("testfft.cpp")'
>> ccache g++ -I/usr/share/R/include
>> -I/usr/local/lib/R/site-library/Rcpp/include     -fpic  -g -O3 -Wall -pipe
>> -pedantic -Wno-variadic-macros -c testfft.cpp -o testfft.o
>> g++ -shared -o testfft.so testfft.o
>> -L/usr/local/lib/R/site-library/Rcpp/lib -lRcpp
>> -Wl,-rpath,/usr/local/lib/R/site-library/Rcpp/lib -L/usr/lib64/R/lib -lR
>> edd at max:/tmp/samperi-gc$ r torture.R
>> Loading required package: methods
>> In case 2
>>  [1] 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i
>> 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i
>> In case 3
>>  [1] 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i
>> 0+0i 0+0i 0+0i 0+0i 0+0i 0+0i
>> still here
>> edd at max:/tmp/samperi-gc$
>>
>> --
>> Dirk Eddelbuettel | edd at debian.org | http://dirk.eddelbuettel.com

I'm sorry to say that I will need to abandon the debugging of this.

I have converted the code in Rcpp/R/exceptions.R to using a R
functions with a common environment to keep track of the error
conditions.  I can get access to those from within the C++ code
through values established during the execution of R_init_Rcpp but the
next time I try to use them in the C++ code they are gone, although
they are still there are the R side.  It is bizarre - I have no idea
what is going on.

Anyway, I need to turn my attention back to lme4a.  I am giving a
short course starting tomorrow and must have a version of lme4a that
can compile and run.  I have been converting it to use Rcpp Modules
and it looks like I will need to strip all that code out.  I hope that
the problems with memory protection are isolated in the Modules
sections of Rcpp.


More information about the Rcpp-devel mailing list