[racket-dev] FFI: pointer to an array in a C struct type

From: Tobias Hammer (tobias.hammer at dlr.de)
Date: Mon Dec 3 06:31:37 EST 2012

On Mon, 03 Dec 2012 11:45:08 +0100, Neil Toronto <neil.toronto at gmail.com>  
wrote:

> This error seems wrong:
>
>
> #lang racket
>
> (require ffi/unsafe
>           ffi/unsafe/cvector)
>
> (define-cstruct _mpz ([alloc _int]
>                        [size _int]
>                        [limbs (_gcable _cvector)]))
>
> (define z (make-mpz 1 1 (list->cvector '(1) _long)))
> (mpz-limbs z)
>
>  >>> _cvector: cannot automatically convert a C pointer to a cvector
>
>
> The error might be correct, though late and confusing, if a cvector's  
> "base representation" isn't a pointer type. Is it?

The base representation should be a pointer but the length and type  
information to convert it back to a cvector is missing. Whats stored  
inside the struct is only a plain pointer, without the information you  
supplied to make-mpz, and because of this _cvector only has a  
racket->c-conversion (see ffi/unsafe/cvector.rkt).

> If that error is correct, then how are FFI users meant to define a C  
> struct that has a "long *" field that points to an array? I've not yet  
> managed to define one whose instances survive a garbage collection cycle  
> without using (_gcable _cvector). Here's one of my desperate attempts:
>
>
> #lang racket
>
> (require ffi/unsafe
>           ffi/unsafe/cvector)
>
> (define-cstruct _mpz ([alloc _int] [size _int] [limbs _gcpointer]))
>
> (define z (make-mpz 1 1 (cvector-ptr (list->cvector '(1) _long))))
>
>  > (ptr-ref (mpz-limbs z) _long 0)
> 1
>  > (collect-garbage)
>  > (ptr-ref (mpz-limbs z) _long 0)
> 139856348920568
>
>
> I mean to be complain-y this time. This shouldn't be this hard to figure  
> out.

I guess the problem here is, that the gc only knows memory with only  
pointers (to gcable memory) inside and (atomic) memory without any  
pointers it should follow. You try to mix them up. make-mpz should malloc  
(see ffi docs) atomic memory and you put a pointer managed by the gc into  
it. The pointer gets relocated on gc, but the ref inside the struct is not  
known and not updated.

I unfortunately don't know a simple, gc- and typesafe way to put pointers  
inside structs. My attempts to get around this were pretty hacking (using  
a raw malloc'd pointer, embed a struct with plain values as pointer inside  
an interor-malloc'd struct together with all others pointers, etc).
I would be really interested in a way to accomplish this, too.

Tobias




-- 
---------------------------------------------------------
Tobias Hammer
DLR / Institute of Robotics and Mechatronics
Muenchner Str. 20, D-82234 Wessling
Tel.: 08153/28-1487
Mail: tobias.hammer at dlr.de

Posted on the dev mailing list.