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

From: Dmitry Pavlov (dpavlov at ipa.nw.ru)
Date: Mon Aug 20 12:31:05 EDT 2012


I am stuck with a Racket<->C linkage problem which manifests
itself at random occasions.

I was able to come up with this short example (ffi-test.rkt)
with which the problem can be analyzed:

#lang racket

(require ffi/unsafe ffi/unsafe/define ffi/unsafe/cvector ffi/vector)

(define libmylib (ffi-lib "/home/dpavlov/libmylib"))
(define-ffi-definer define-libintegrator libmylib)
(define _handler (_fun _int _pointer -> _int))
(define-libintegrator myfunc (_fun _int _pointer _handler -> _int))

(define (make-myhandler)
   (let ((counter 0))
     (lambda (len ptr)
       (printf "call #~a\n" counter)
       (set! counter (add1 counter))
       (let ((vec (make-cvector* ptr _double len)))
         (for ((i (in-range len)))
           (cvector-set! vec i (* (cvector-ref vec i) 2))))

(define myhandler (make-myhandler))

(define (f64vector->vector v)
   (let ((res (make-vector (f64vector-length v))))
     (for ((i (in-range 0 (f64vector-length v))))
       (vector-set! res i (f64vector-ref v i)))

(define (test)
   (let ((vec (make-f64vector 3)))
     (f64vector-set! vec 0 1.0)
     (f64vector-set! vec 1 2.0)
     (f64vector-set! vec 2 3.0)
     (myfunc 3 (f64vector->cpointer vec) myhandler)
     (f64vector->vector vec)))

The contents of mylib.c is just a function which calls
back the callback that was passed from Racket:

int myfunc (int length, double *x, int (*handler) (int length, double *arr))
   handler(length, x);
   return 0;

The command to compile the library was the following:
gcc -shared -fPIC -o libmylib.so mylib.c

I have Racket 5.3 on 64-bit Debian unstable.

Now the problem: I load the ffi-test.rkt in DrRacket,
then Ctrl+R, then I start putting (test) calls into the
interactions windows. It starts fine (properly producing
2,4,6 from 1,2,3) but sooner or later it gives the
original 1,2,3 array. Here is how it looks like:

Welcome to DrRacket, version 5.3 [3m].
Language: racket [custom]; memory limit: 256 MB.
 > (test)
call #0
'#(2.0 4.0 6.0)
 > (test)
call #1
'#(2.0 4.0 6.0)
 > (test)
call #2
'#(2.0 4.0 6.0)
 > (test)
call #3
'#(2.0 4.0 6.0)
 > (test)
call #4
'#(2.0 4.0 6.0)
 > (test)
call #5
'#(1.0 2.0 3.0)
 > (test)
call #6
'#(2.0 4.0 6.0)

Call #5 has failed in this case; it might as well be #12
or #26, the number is different every time.

So something is happening with f64vectors traveling between
Racket and C. Maybe some evil kind of GC interference,
I do not know. Please, any ideas from developers who know
how Racket FFI works! I did a lot of debug-printing, and
it did not give me any clues. The calls to myfunc()
are never missed, but the calling procedure ignores the
changed vector sometimes.

Best regards,


Posted on the users mailing list.