Offhand, I'd say that if "all protects get unprotected before
return"
mydata->ans is not protected against garbage collection, and thus very likely
collected and reused. If mydata is created by Calloc, the GC has no way of
knowing that it might have pointers to things that are intended to persist.
I haven't played with external pointers for a while, but I'd expect that
you'd need to retain a PROTECT on mydata->ans, and then UNPROTECT_PTR or
so in the finalizer.
-pd
On 16 Dec 2013, at 04:11 , Krzysztof Mlynarczyk <mitomaster at gmail.com>
wrote:
> Dear Developers,
>
>
> I've been struggling through writing R extension in C. I've been
using
> an external pointer to store my data (please see sample below). I
> encountered a very weird erroneous behaviour: when I tried to use my
> external pointer to a structure holding several types of data,
> including SEXPs, I discovered that SEXPs change their types between
> returning from initialization function and another one that uses the
> pointer.
>
> sample R code:
>
> # initializing
> a <- init_my_ptr(fname)
>
> # reading more data: error!
> df <- read_my_data(a)
>
> data structure in C:
> typedef struct {
> SEXP ans, ans_nms, R_z, R_a, R_b, R_c;
> FTYPE *datafile;
> char *fname;
> float *a, *b, *c;
> int f_type;
> float t, p, l;
> int st, na, result, bFlags;
> XXX z;
> } my_data_ptr;
>
> // In a C function initializing the external pointer:
> my_data_ptr *mydata = Calloc( 1, my_data_ptr ) ;
> SEXP Rdata;
> PROTECT(Rdata = R_MakeExternalPtr( mydata, R_fname, R_NilValue ));
> ...
> mydata->a = Calloc(mydata->na, float);
> // same for b and c
> // initializing names so that I could use e.g. df$a where df is
> returned by read_my_data()
> PROTECT(mydata->ans_nms = Rf_allocVector(STRSXP, efldNR ));
> for( ix = 0; ix < efldNR; ix++ )
> SET_STRING_ELT(mydata->ans_nms, ix, mkChar(vnames[ix]));
>
> // later I bind values of non-R variables from my data structure to a
> proper vector
> PROTECT(mydata->ans = Rf_allocVector(VECSXP, efldNR ));
>
> Rf_setAttrib(mydata->ans, R_NamesSymbol, mytraj->ans_nms);
> SET_VECTOR_ELT(mydata->ans, 0, mydata->R_a );
> SET_VECTOR_ELT(mydata->ans, 1, mydata->R_b );
> ...
> // all protects get unprotected before return
> // finalizer is registered as well
> return Rdata;
>
> Later on in read_my_data() I read the pointer:
> my_data_ptr *mydata = (my_data_ptr*) R_ExternalPtrAddr(Rdata);
>
> // and REAL(mydata->R_a) yields error since TYPEOF(mydata->R_a) is
not
> REALSXP as it should be but RAWSXP for some reason // (sometimes it's
> STRSXP or INTSXP while it should always be REALSXP)
> // The error message says:
> // REAL() can only be applied to a 'numeric', not a 'raw'
>
> // mydata->ans is the object returned to R where all the data is made
> available to R user:
> return mydata->ans;
>
> // end of example code
>
> Could you please point the possible reasons for the error along with
> the ways of fixing this issue? I've been trying in R-3.0.2, 3.0.1 and
> even 2.15 -- the problem happens in each of them.
>
>
> Regards,
> Christopher
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
--
Peter Dalgaard, Professor
Center for Statistics, Copenhagen Business School
Solbjerg Plads 3, 2000 Frederiksberg, Denmark
Phone: (+45)38153501
Email: pd.mes at cbs.dk Priv: PDalgd at gmail.com