[Rcpp-devel] Segfault error during simulation in Rcpp: explanation/fix

JJ Allaire jj.allaire at gmail.com
Sat May 18 03:51:05 CEST 2013


Ben,

Thanks SO much for the work you did to discover this problem. I've
committed a fix in rev 4319 (also bumped the version to 0.10.3.3 so a new
tarball will also be available from R-forge soon).

Best,

J.J.

On Fri, May 17, 2013 at 8:12 AM, QRD <qrd at sig.com> wrote:

> Hi,
>
> On Thu, May 16, 2013 at 11:02 AM, Dirk Eddelbuettel <edd at debian.org>
> wrote:
> > Here is the self-contained example I asked for.
> >
> > And yes, it crashes for me too.  So let's not create 1e6 temp matrices.
> > Until someone has time to debug memory management internals.  Which is
> > really hard, so this may not get fixed for a while.  Sorry.
> >
> > #!/usr/bin/Rscript
> >
> > library(Rcpp)
> > myFun <- cppFunction('NumericMatrix myFun(NumericMatrix input, int n){
> >   NumericMatrix A(n, n);
> >   for(int Row = 0; Row < n; Row++) {
> >     for(int Col = 0; Col < n; Col++) {
> >       A(Row, Col) = input(Row, Col);
> >     }
> >   }
> >   return A;
> > }')
> >
> > n <- 10
> > x <- 1:n^2
> > N <- 1e6
> > b <- 0
> > for (j in 1:N) {
> >     means <- matrix(x, n, n)
> >     res <- myFun(means, n)
> >     a <- res[1, 1]
> >     b <- b + a
> > }
> >
> > cat(sprintf("Done, b is %d\n", b))
>
> I had a look at this, and I think I see what's going on.
>
> The error is reproducible much more quickly under gctorture(), and then
> working directly with the generated code in its own C++ file, I was able
> to cut it down to:
>
> - - - - 8< - - - - crash-fn.r
>
> require(methods)
> require(Rcpp)
>
> dll.info <- dyn.load("crash-fn")
> mod <- Module("Crash", dll.info, mustStart = TRUE)
> myFun <- mod$myFun
>
> N <- 25
> b <- 0
>
> for (j in 1:N) {
>     gctorture(TRUE)
>     res <- myFun()
>     gctorture(FALSE)
>     b <- b + res[1]
> }
>
> - - - - 8< - - - - crash-fn.cpp
>
> #include <Rcpp.h>
>
> static SEXP myFun()
> {
>     Rcpp::RNGScope __rngScope;
>     Rcpp::NumericMatrix __result(5, 5);
>
>     return Rcpp::wrap(__result);
> }
>
> RCPP_MODULE(Crash)
> {
>     Rcpp::function("myFun", &myFun);
> }
>
> - - - - 8< - - - -
>
> Then:
>
>     R CMD SHLIB crash-fn.cpp && Rscript crash-fn.r
>
> reliably and quickly crashes.
>
> I think what happens is that the
>
>     return Rcpp::wrap(__result);
>
> line at the end of the function pulls the m_sexp out of the
> NumericMatrix (because a NumericMatrix is an RObject) via
>
>     inline operator SEXP() const { return m_sexp ; }
>
> and gets ready to return it.  But before the 'return' actually happens,
> the destructors for the NumericMatrix and the RNGScope get called, in
> that order.  The NumericMatrix destructor releases its underlying SEXP,
> via the base class destructor
>
>     RObject::~RObject() {
>         RCPP_DEBUG_1("~RObject(<%p>)", m_sexp)
>         Rcpp_ReleaseObject(m_sexp) ;
>     }
>
> and now our return-value SEXP is unprotected.  The destructor of
> RNGScope then runs, calling PutRNGstate(), where (reliably under
> gctorture(); very occasionally without this) our result SEXP gets
> re-allocated, or otherwise stomped on.
>
> If you swap the order of the declarations of __rngScope and __result,
> the code runs correctly, supporting this explanation.
>
> As for a fix, one way would be to wrap an extra scope round the main
> body of the generated code and PROTECT the wrapped result.  This works
> in my cut-down example:
>
>     static SEXP myFun()
>     {
>         SEXP __sexp_result;
>         {
>             Rcpp::RNGScope __rngScope;
>             Rcpp::NumericMatrix __result(5, 5);
>
>             PROTECT(__sexp_result = Rcpp::wrap(__result));
>         }
>         UNPROTECT(1);
>         return __sexp_result;
>     }
>
> and the generated code could instead be
>
>     RcppExport SEXP sourceCpp_78413_myFun(SEXP inputSEXP, SEXP nSEXP) {
>     BEGIN_RCPP
>         SEXP __sexp_result;
>         {
>             Rcpp::RNGScope __rngScope;
>             NumericMatrix input = Rcpp::as<NumericMatrix >(inputSEXP);
>             int n = Rcpp::as<int >(nSEXP);
>             NumericMatrix __result = myFun(input, n);
>             PROTECT(__sexp_result = Rcpp::wrap(__result));
>         }
>         UNPROTECT(1);
>         return __sexp_result;
>     END_RCPP
>     }
>
> I'm not fully familiar with how the C++ code gets generated, but perhaps
> somebody who is could implement this or similar fix?
>
> Thanks,
>
> Ben.
> _______________________________________________
> Rcpp-devel mailing list
> Rcpp-devel at lists.r-forge.r-project.org
> https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20130517/a9561808/attachment.html>


More information about the Rcpp-devel mailing list