[racket] Freeing FFI resources

From: Jon Zeppieri (zeppieri at gmail.com)
Date: Sun Oct 10 20:39:57 EDT 2010

On Sun, Oct 10, 2010 at 5:40 PM, Eric Dobson <endobson at cs.brown.edu> wrote:
> I am dealing with a foreign library that has functions that return
> error messages in a char** input argument. These need to be explicitly
> freed by calling another function. I figured out how to get them into
> racket strings by using the _ptr and the _string ctype. But I didn't
> see a way to capture the value before conversion to a racket string so
> that I could free the original string, and continue to use the _string
> conversion process. Is there an easy way to do these two thing
> together?

There's a section of the FFI manual (Pointer Functions -> Memory
Management) that uses this scenario (or one very similar) as an
example:

http://docs.racket-lang.org/foreign/foreign_pointer-funcs.html?q=ffi&q=syntax-rules&q=define-syntax#(part._.Memory_.Management)

See the definition of the bytes/free ctype -- as well as the
discussion about why the code there is subtly incorrect.


Or, rather than using a finalizer (and assuming you want a character
string as output, not a byte string), you could use
bytes->string/[encoding] to produce a character string, then free the
original byte string and return the character string.

So let's say you have the following, contrived C functions:

int fail();
void get_err_msg(int, char**);
void free_err_msg(char *);

fail() just returns an error code, which you can pass to get_err_msg()
to get the corresponding string message. And you're supposed to free
the messages by passing them to free_err_msg().

Then, you can create bindings like so:

======================
#lang racket

(require ffi/unsafe)

;; create a byte string from a pointer
;;
;; make-byte-string : _pointer -> _bytes
(define (make-byte-string ptr)
  (let loop ((i 0))
    (cond ((zero? (ptr-ref ptr _byte i))
           (make-sized-byte-string ptr i))
          (else
           (loop (add1 i))))))

;; A ctype meant to be used as an out param for strings
;; that are allocated by the library
;;
;; _out-string : _ctype
(define _out-string
    (make-ctype _pointer
                #f
                (lambda (x)
                  (let* ([b (make-byte-string x)]
                         [s (bytes->string/latin-1 b)])
                    (free-err-msg x)
                    s))))


(define libtest (ffi-lib "/path/to/shared/lib"))

(define fail (get-ffi-obj "fail" libtest
                          (_fun -> _int)))

(define get-err-msg (get-ffi-obj "get_err_msg" libtest
                                 (_fun _int (s : (_ptr o _out-string))
-> _void -> s)))

(define free-err-msg (get-ffi-obj "free_err_msg" libtest
                                  (_fun _pointer -> _void)))







>
> -Eric
> _________________________________________________
>  For list-related administrative tasks:
>  http://lists.racket-lang.org/listinfo/users
>


Posted on the users mailing list.