[Rcpp-devel] tracking volatile bug

Serguei Sokol serguei.sokol at gmail.com
Fri Nov 21 18:23:26 CET 2014


Well, I could narrow the issue but not yet resolve it.

Le 18/11/2014 20:46, William Dunlap a écrit :
>> I will try "gctorture(TRUE)" suggested by Martin.
I'll start with this easy part. Unfortunately valgrind
didn't detect any wrong access to memory.

Now, the difficult part.
The most reduced code in cpp producing an error under
gctorture(TRUE) is the following:
8<------------file matrix_norm.cpp
//[[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
using namespace Rcpp;
using namespace arma;

// [[Rcpp::export]]
SEXP nmat(mat A) {
    Function Matrix_norm_r_=Environment("package:Matrix")["norm"];
    SEXP s=wrap("1");
    Rf_PrintValue(s);
    SEXP res=Matrix_norm_r_(wrap(A), s);
    return res;
}
8<------------

It is compiled with "CXXFLAGS=-g -O0 -std=c++11" in ~/.R/Makevars
The R-3.1.2 itself is also compiled with "-g -O0 -std=c++11" by
gcc version 4.8.2

How to reproduce ?
$ R -d gdb
(gdb) run
 > library(Rcpp)
 > library(Matrix)
 > sourceCpp("matrix_norm.cpp")
 > [Ctrl-C]
(gdb) b nmat
Breakpoint 1 at 0x7ffff079c253: file matrix_norm.cpp, line 8.
(gdb) c
Continuing.
nmat(as.matrix(pi))

Breakpoint 1, nmat (A=...) at matrix_norm.cpp:8
8          Function Matrix_norm_r_=Environment("package:Matrix")["norm"];
(gdb) c
Continuing.
[1] "1"
[1] 3.141593
This is a correct result. Now, push it to an error with gctorture
 > gctorture(TRUE)
 > nmat(as.matrix(pi))

Breakpoint 1, nmat (A=...) at matrix_norm.cpp:8
8          Function Matrix_norm_r_=Environment("package:Matrix")["norm"];
(gdb) c
Continuing.
<CHARSXP: "<NA>">
Erreur : erreur d'évaluation de l'argument 'type' lors de la sélection d'une méthode pour la fonction 'norm' : Erreur : type 'char' indisponible dans 'eval'

The wrong behavior is manifested in printing '<CHARSXP: "<NA>">'
It means that the string "1" was not wrapped correctly. The error messages
(here in french but never mind) are just a consequence of the wrong string
parameter passed to a call Matrix::norm(). I must say that in a function
without evoking the Matrix environment but doing just a plain
wrap("1"), the wrap() is working as expected.
At one moment I suspected that the problem was in Rf_mkString() where there
is a call to unprotected mkChar(), so in R-3.1.2/src/include/Rinlinedfuns.h:682
I replaced
SET_STRING_ELT(t, (R_xlen_t)0, mkChar(s));
by
SET_STRING_ELT(t, (R_xlen_t)0, PROTECT(mkChar(s)));
and consequent UNPROTECT(1) by UNPROTECT(2)
But ... adding this protection did not resolve the issue.

 > nmat(as.matrix(pi))

Breakpoint 1, nmat (A=...) at matrix_norm.cpp:8
8          Function Matrix_norm_r_=Environment("package:Matrix")["norm"];
(gdb) n
9          SEXP s=wrap("1");
(gdb) s
Rcpp::wrap (v=0x7ffff07a1a5a "1")
     at /home/local/src/R-3.1.2/library/Rcpp/include/Rcpp/internal/wrap.h:930
930             if (v != NULL)
(gdb)
931                     return Rf_mkString(v) ;
(gdb) s
Rf_mkString (s=0x7ffff07a1a5a "1") at ../../src/include/Rinlinedfuns.h:681
681         PROTECT(t = allocVector(STRSXP, (R_xlen_t)1));
(gdb) n
682         SET_STRING_ELT(t, (R_xlen_t)0, PROTECT(mkChar(s)));
(gdb)
683         UNPROTECT(2);
(gdb)
684         return t;
(gdb) call Rf_PrintValue(t)
<CHARSXP: "<NA>">
instead of a correct "1".
My problem to locate the place where a pointer corruption occurs is that
if I dig deep enough to see what is going on on the stack of protected values
and during memory allocation, it ... produce a good result, i.e. a string
vector with a single element "1".
 > nmat(as.matrix(pi))

Breakpoint 1, nmat (A=...) at matrix_norm.cpp:8
8          Function Matrix_norm_r_=Environment("package:Matrix")["norm"];
(gdb) n
9          SEXP s=wrap("1");
(gdb) s
Rcpp::wrap (v=0x7ffff07a1a5a "1")
     at /home/local/src/R-3.1.2/library/Rcpp/include/Rcpp/internal/wrap.h:930
930             if (v != NULL)
(gdb)
931                     return Rf_mkString(v) ;
(gdb)
Rf_mkString (s=0x7ffff07a1a5a "1") at ../../src/include/Rinlinedfuns.h:681
681         PROTECT(t = allocVector(STRSXP, (R_xlen_t)1));
(gdb) n
682         SET_STRING_ELT(t, (R_xlen_t)0, PROTECT(mkChar(s)));
(gdb) s
Rf_mkChar (name=0x7ffff07a1a5a "1") at envir.c:3444
3444        size_t len =  strlen(name);
(gdb) p name
$8 = 0x7ffff07a1a5a "1"
(gdb) finish
Run till exit from #0  Rf_mkChar (name=0x7ffff07a1a5a "1") at envir.c:3444
0x00007ffff78ef4f6 in Rf_mkString (s=0x7ffff07a1a5a "1") at ../../src/include/Rinlinedfuns.h:682
682         SET_STRING_ELT(t, (R_xlen_t)0, PROTECT(mkChar(s)));
Value returned is $9 = (struct SEXPREC *) 0x48bf4c8
(gdb) call Rf_PrintValue(0x48bf4c8)
<CHARSXP: "1">
(gdb) n
683         UNPROTECT(2);
(gdb)
684         return t;
(gdb) call Rf_PrintValue(t)
[1] "1"
(gdb) c
Continuing.
[1] "1"
[1] 3.141593

But immediately after:
 > nmat(as.matrix(pi))

Breakpoint 1, nmat (A=...) at matrix_norm.cpp:8
8          Function Matrix_norm_r_=Environment("package:Matrix")["norm"];
(gdb) c
Continuing.
<CHARSXP: "<NA>">
Erreur : erreur d'évaluation de l'argument 'type' lors de la sélection d'une méthode pour la fonction 'norm' : Erreur : type 'char' indisponible dans 'eval'

Any thoughts how to locate this problem with pointer corruption?

Serguei.


More information about the Rcpp-devel mailing list