[plt-scheme] FFI and pointer manipulations

From: Jens Axel Søgaard (jensaxel at soegaard.net)
Date: Sun Feb 11 15:06:43 EST 2007

Eli Barzilay wrote:

>On Feb 11, Jens Axel Søgaard wrote:
>>Eli Barzilay wrote:
>>>On Feb  9, Jens Axel Søgaard wrote:
>>ould calculate the md5 of the 3 bytes 2 3 4.
>>I can't figure out what to write instead of <cpointer-to-bs+2>.
>Here's an example of what you want -- I have this function in x.so:
>  void foo(char *a) { printf("received %d: \"%s\"\n", (int)a, a); }
>and I do this interaction in MzScheme which should make it clear how
>to play with pointers:
>  > (define p (get-ffi-obj "foo" "~/tmp/x.so" (_fun _pointer -> _void)))
>  > (define buf #"0123456789")
>  > (p buf)
>  received 180307632: "0123456789"
>  > (define tmp (malloc (max (ctype-sizeof _int) (ctype-sizeof _pointer))))
>  > (ptr-set! tmp _pointer buf)
>  > (ptr-ref tmp _int)
>  180307632
>  > (ptr-set! tmp _int (+ 3 (ptr-ref tmp _int)))
>  > (ptr-ref tmp _int)
>  180307635
Okay, got it.

>>>This is intentional.  Having a pointer to the middle of a malloced
>>>object will not work right with 3m.  In fact, I think that it may
>>>cause damage even if you use it in some harmless way.  One way to
>>>deal with this would be to provide a kind of pointer-with-offset,
>>>and another would be to add a new kind of "dangerous pointer" type.
>>>Both will not be easy to understand and to use, and nothing is
>>>implemented yet.
>>It is the pointer-with-offset I need. In my case the C code doesn't
>>store the pointer, so it ought to be safe.
>The fact that C doesn't store the pointer is not too relevant -- you
>have to be very careful for everything that is done in Scheme code,
>because as long as you're there a GC can happen -- and in 3m this
>means that pointers are likely to change.  Here's an example that
>demonstrates this:
Okay, that's why you mentioned the possibility of having an 
pointer+offset type, so that
the FFI could be responsible for the pointer arithmetic.

>Moreover, according to what Matthew told me (which might not be true
>now), it can even make the GC crash because something it thinks is a
>pointer to a block of memory is actually pointing to the middle of a
>real object.
Yours and Matthew's post make it clear, that I can't use (bytes ...) to 
allocate my byte
string, since 3m might move it. Can I instead use malloc with either the 
mode 'eternal
or 'raw ? That is, is the following supposed to work?

(require (planet "digest.ss" ("soegaard" "digest.plt"))
         (lib "foreign.ss"))

; allocate an unmovable array
(define unmovable-bytes (malloc 100 'eternal))
(define u unmovable-bytes)

; store #"abcde" into the array
(ptr-set! u _byte 'abs 0 (char->integer #\a))
(ptr-set! u _byte 'abs 1 (char->integer #\b))
(ptr-set! u _byte 'abs 2 (char->integer #\c))
(ptr-set! u _byte 'abs 3 (char->integer #\d))
(ptr-set! u _byte 'abs 4 (char->integer #\e))

; test, that the store worked
(md5 #"ab")
(md5 (make-sized-byte-string u 2))

; u+i : natural -> cpointer
;   return pointer to the i'th byte of the array u
(define u+i
  (let ([*u (malloc (max (ctype-sizeof _int) (ctype-sizeof _pointer)))])
    (ptr-set! *u _pointer u)
    (let* ([*u_int (ptr-ref *u _int)]
           [*u+i (malloc (max (ctype-sizeof _int) (ctype-sizeof 
      (lambda (i)
        (ptr-set! *u+i _int (+ *u_int i))
        (ptr-ref *u+i _pointer)))))

; test whether u+i works
(md5 #"bc")
(md5 (make-sized-byte-string (u+i 1) 2))

Jens Axel Søgaard

Posted on the users mailing list.