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