[R] .Call setAttrib(ans,R_DimSymbol,dim); Crashes.

Douglas Bates bates at stat.wisc.edu
Wed Feb 11 18:58:51 CET 2004


"wolski" <wolski at molgen.mpg.de> writes:

> I want to return a matrix. The code does the R interfacing.  This
> version does it fine.
> 
>   SEXP ans,dim;
>   PROTECT(ans = NEW_NUMERIC(count*2));
>   memcpy(NUMERIC_POINTER(ans),result,count*sizeof(double));
>   memcpy(&(NUMERIC_POINTER(ans)[count]),occur,count*sizeof(double));
> /**  PROTECT(dim=NEW_INTEGER(2));
>     INTEGER_POINTER(dim)[0]=2;
>    INTEGER_POINTER(dim)[1]=count; 
>    setAttrib(ans,R_DimSymbol,dim); 
> */
>   UNPROTECT(7);
> 
> If I uncomment the lines 5 to 8 than all is working fine four small
> count's (tested 10,20).  But if the result is an array with about
> 2000 entries R crashes vicious and violently with the lax comment
> 
> Process R trace trap at Wed Feb 11 13:55:45 2004
> 
> Anyone is seeiing something what I can not see?

In most cases it is easier to use allocMatrix instead of assigning a
dimension attribute to a numeric vector.  You could write this as

   SEXP ans = PROTECT(allocMatrix(REALSXP, 2, count));
   memcpy(NUMERIC_POINTER(ans),result,count*sizeof(double));
   memcpy(&(NUMERIC_POINTER(ans)[count]),occur,count*sizeof(double));
   UNPROTECT(1);

Another enhancement is use Memcpy, as in

   SEXP ans = PROTECT(allocMatrix(REALSXP, 2, count));
   double *ansp = REAL(ans);    /* same as NUMERIC_POINTER(ans) */

   Memcpy(ansp, result, count);
   Memcpy(ansp + count, occur, count);
   UNPROTECT(1);

Regarding your particular problem, did you happen to change the
argument to UNPROTECT when you changed the code?  You may be getting a
stack imbalance if you change the number of PROTECTs that are executed
and don't change the UNPROTECT count.

This is why I generally try to write C functions with only one PROTECT
in then.  Because PROTECTing an object also PROTECTs all components
reachable from that object I allocate other storage as components of
the (PROTECT'ed) result then manipulate those components.  For
example, if I don't use allocMatrix I would write what you did as

   SEXP ans = PROTECT(NEW_NUMERIC(count * 2));
   double *ansp = NUMERIC_POINTER(ans);
   int *dims;

   Memcpy(ansp, result, count);
   Memcpy(ansp + count, occur, count);
   setAttrib(ans, R_DimSymbol, NEW_INTEGER(2));
   dims = INTEGER_POINTER(getAttrib(ans, R_DimSymbol));
   dims[0] = 2;
   dims[1] = count;
   UNPROTECT(1);

It is a matter of taste whether you prefer to assign the component
then select it or to allocate the component by itself and remember to
PROTECT and UNPROTECT it.  Both are a bit tedious but I find the
former to be less error-prone.

If you look at the C sources for the new Matrix_0.6 package (in the
1.9 contributed section on CRAN) you will see that just about every C
function that returns an SEXP ends with

   UNPROTECT(1);
   return ans;

-- 
Douglas Bates                            bates at stat.wisc.edu
Statistics Department                    608/262-2598
University of Wisconsin - Madison        http://www.stat.wisc.edu/~bates/




More information about the R-help mailing list