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

Romain Francois romain at r-enthusiasts.com
Tue Jan 11 19:57:14 CET 2011


Le 11/01/11 19:46, Douglas Bates a écrit :
> On Tue, Jan 11, 2011 at 12:27 PM, Dominick Samperi<djsamperi at gmail.com>  wrote:
>>
>>
>> On Tue, Jan 11, 2011 at 1:20 PM, Romain Francois<romain at r-enthusiasts.com>
>> wrote:
>>>
>>> Le 11/01/11 19:12, Davor Cubranic a écrit :
>>>>
>>>> I think an important point from Doug has been lost in the subsequent
>>>> 20-odd messages of flamebombing:
>>>>
>>>>>> 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.
>>>>>>
>>>>>> 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.
>>>>>
>>>>> I don't think so.  In the situation that Dominick is describing the C
>>>>> API is being used (calls to Rf_install, Rf_lang1, Rf_eval, ...) and
>>>>> you have to play by the rules of the C API.  Essentially every time
>>>>> that you call a function in the C API that can cause a memory
>>>>> allocation you are open yourself to the possibility of having the
>>>>> garbage collector run and getting unprotected SEXPs blown away.  And,
>>>>> naturally, Rf_eval can cause memory allocation.
>>>>>
>>>>> I understood Dominick to be saying that in the code related to Modules
>>>>> and the evaluator and all that which we have been trying to debug
>>>>> there are such cases of the use of the C API that are unsafe.
>>>>
>>>> Can anyone comment whether this is correct?
>>>>
>>>> Davor
>>>
>>> Yep. Doug's analysis is right. Rcpp is implemented with the C R API, and
>>> apparently there were a few places where we were not careful enough. Most
>>> notably in calls to Rf_lcons and Rf_cons. This has been partially dealt with
>>> today.
>>
>> Just for the record, Doug is summarizing my analysis, based on several
>> examples that I posted to this thread,
>> and that I am pleased to see have inspired some remedial action.
>
> Sorry for not responding earlier.  I'm in the middle of teaching a short course.
>
> Dominick is correct that it was his analysis that picked up the
> failures to PROTECT/UNPROTECT in cases that were causing at least some
> of the problems with loading Modules.  Credit where credit is due.
>
>   As Romain has indicated, some of the problems have been fixed but
> apparently problems still remain.  Debugging memory protection
> problems is often very difficult.

It is. Not sure what is my next step here. Remaining problems seem not 
directly related to Rcpp, but rather associated with lazy loading. See:

 > require(inline)
Le chargement a nécessité le package : inline
 > require(Rcpp)
Le chargement a nécessité le package : Rcpp
 > inc <- '
+
+ class Randomizer {
+ public:
+
+     // Randomizer() : min(0), max(1){}
+     Randomizer( double min_, double max_) : min(min_), max(max_){}
+
+     NumericVector get( int n ){
+         RNGScope scope ;
+         return runif( n, min, max );
+     }
+
+ private:
+     double min, max ;
+ } ;
+
+ RCPP_MODULE(mod){
+
+     class_<Randomizer>( "Randomizer" )
+
+         // No default: .default_constructor()
+         .constructor<double,double>()
+
+         .method( "get" , &Randomizer::get ) ;
+
+ }
+ '
 >     fx <- cxxfunction( , '', includes = inc, plugin = "Rcpp" )
 >
 > mod <- Module( "mod", getDynLib( fx ) )
 > gctorture(TRUE)
 > Rcpp:::.getModulePointer( mod )
Erreur dans list(c(162342L, 224L), 
"/Library/Frameworks/R.framework/Resources/library/base/R/base.rdb", 
TRUE, function (n)  :
   le premier argument doit être une liste nommée
De plus : Messages d'avis :
1: In asMethod(object) : NAs introduits lors de la conversion automatique
2: In asMethod(object) : NAs introduits lors de la conversion automatique
 > traceback()
8: list(c(162342L, 224L), 
"/Library/Frameworks/R.framework/Resources/library/base/R/base.rdb", 
TRUE, function (n)
    {
        if (existsInFrame(n, envenv)) getFromFrame(n, envenv) else {
            e <- mkenv()
            set(n, e, envenv)
            key <- getFromFrame(n, env)
            data <- lazyLoadDBfetch(key, datafile, compressed, envhook)
            if (is.null(data$enclos)) parent.env(e) <- emptyenv() else 
parent.env(e) <- data$enclos
            vars <- names(data$bindings)
            for (i in seq_along(vars)) set(vars[i], data$bindings[[i]],
                e)
            if (!is.null(data$attributes)) attributes(e) <- data$attributes
            if (!is.null(data$isS4) && data$isS4) .Call("R_setS4Object",
                e, TRUE, TRUE, PACKAGE = "base")
            if (!is.null(data$locked) && data$locked) 
.Internal(lockEnvironment(e,
                FALSE))
            e
        }
    })
7: asEnv(refMethods)
6: initialize(value, ...)
5: initialize(value, ...)
4: new("refClassRepresentation", getClassDef(Class, where = where),
        fieldClasses = fieldClasses, refMethods = asEnv(refMethods),
        fieldPrototypes = asEnv(fieldPrototypes), refSuperClasses = 
refSuperClasses)
3: setRefClass(clname, fields = fields, contains = "C++Object",
        methods = methods, where = where)
2: Module(module, mustStart = TRUE)
1: Rcpp:::.getModulePointer(mod)

Romain

> As Dirk indicated, the use of C++ helps by removing much of the tedium
> of memory allocation and freeing.  However, until R is rewritten in
> C++, there will still be these difficulties with going through R's API
> based on C.
>
>>>
>>> This is not completely over though apparently. The code below still does
>>> not support the torture.
>>>
>>> To be continued ...
>>>
>>> Romain
>>>
>>>
>>>
>>>
>>> require(inline)
>>> require(Rcpp)
>>> inc<- '
>>>
>>> class Randomizer {
>>> public:
>>>
>>>     // Randomizer() : min(0), max(1){}
>>>     Randomizer( double min_, double max_) : min(min_), max(max_){}
>>>
>>>     NumericVector get( int n ){
>>>         RNGScope scope ;
>>>         return runif( n, min, max );
>>>     }
>>>
>>> private:
>>>     double min, max ;
>>> } ;
>>>
>>> RCPP_MODULE(mod){
>>>
>>>     class_<Randomizer>( "Randomizer" )
>>>
>>>         // No default: .default_constructor()
>>>         .constructor<double,double>()
>>>
>>>         .method( "get" ,&Randomizer::get ) ;
>>>
>>> }
>>> '
>>>     fx<- cxxfunction( , '', includes = inc, plugin = "Rcpp" )
>>>
>>> mod<- Module( "mod", getDynLib( fx ) )
>>> gctorture(TRUE)
>>> Rcpp:::.getModulePointer( mod )
>>>
>>>
>


-- 
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30
http://romainfrancois.blog.free.fr
|- http://bit.ly/fT2rZM : highlight 0.2-5
|- http://bit.ly/gpCSpH : Evolution of Rcpp code size
`- http://bit.ly/hovakS : RcppGSL initial release




More information about the Rcpp-devel mailing list