Skip to content

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

3 messages · QRD, Dirk Eddelbuettel, JJ Allaire

QRD
#
Hi,
On Thu, May 16, 2013 at 11:02 AM, Dirk Eddelbuettel <edd at debian.org> wrote:
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.
#
Hi Ben,

Those two emails rocked!  I will have a bit of latency as I am now at
R/Finance, but we will apply the simple patch and check the suggested.
Thanks a bunch for doing that legwork!

Dirk
#
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:

            
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20130517/a9561808/attachment.html>