[racket] Trouble with C->Racket callbacks passing pointers to arrays

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Mon Aug 20 14:31:27 EDT 2012

At Mon, 20 Aug 2012 21:56:40 +0400, Dmitry Pavlov wrote:
> However, it seems that I have a similar problem with a callback
> that fills an array malloc()-ed in the C library, and I am stupid
> enough not to understand why it fails, again.
> Could you please take a look at this:
> 
> int myfunc2 (int length, double *x, int (*filler) (int length, double *arr))
> {
>     double *buf = (double *)malloc(length * sizeof(double));
>     filler(length, buf);
>     memcpy(x, buf, length * sizeof(double));
>     free(buf);
>     return 0;
> }

The problem in this case is that the C code receives a pointer `x' to a
GC-managed object, and the object at that memory moves during the
callback to filler(), so that memcpy(x, ....) copies to the wrong
place.

Assuming that your C code will remain oblivious to GC, you'll have to
change the call to myfunc2() to pass a reference to an object that is
either not GC-managed or won't be moved by a GC (i.e., allocated using
'atomic-interior mode):

 (define (make-f64vector/immobile n)
   (cast (malloc n _double 'atomic-interior)
         _pointer
         (_gcable (_f64vector o n))))

 (define (test2)
    (let ((vec (make-f64vector/immobile 3)))
       ....))


This example illustrates a general problem with foreign functions and
callbacks: since a GC is possible during the callback, you have to pass
the foreign function only references to things that a GC won't move.


Posted on the users mailing list.