FFI Ptr question
Alastair Reid
alastair@reid-hoffmann.net
Thu, 3 Jul 2003 11:42:30 +0100
paul@theV.net wrote:
> If a C function returns a (void*), let's say:
>
> data MyObj = MyObj
>
> foreign import ccall "static myobj_ffi.h new_obj"
> newMyObject :: IO (Ptr MyObj)
>
> ptr <- newMyObject
>
> should I free the ptr afterwards or not?
There's no single right answer to this - it all depends on the function.
Here's three functions which return very different kinds of pointer.
(They're somewhat bogus in other ways but are representative of real, useful
functions.)
Statically allocated - do not free
T* newMyObject(void) { static T x; return &x; }
Allocated with malloc - use free to release it
T* newMyObject(void) { return (T*)malloc(sizeof T); }
Reference counted - do not free
T* newMyObject(void) { T* x = malloc(sizeof T); x->ref_count=1; return x; }
There's several further variants like allocating from a separate memory pool.
Basically, you have to carefully read the documentation of every function to
find out how to release objects. Since documentation is often poor, you
might also study the implementation or uses and you should get in the habit
of always checking error codes (even on functions like printf which most C
programmers have never checked in their life) because it will help find those
cases where the documentation is wrong or incomplete.
> If I have another imported C function:
>
> foreign import ccall "static myobj_ffi.h print_obj"
> printMyObject :: Ptr MyObj -> IO ()
>
> Can I safely assume the C function print_obj(void *) always get the
> same pointer even if I call (printMyObject ptr) multiple times?
If you have:
do
printMyObject ptr
...
printMyObject ptr
...
printMyObject ptr
Then all three uses see the same pointer no matter what happens between the
calls (assuming you dont use 'let ptr = ...' in the dots, of course).
To put it another way, anything of type 'Ptr a' is an abstract type as far as
Haskell is concerned. It is just a 32-bit object (or 64 or whatever) which
Haskell doesn't directly understand. All it can do with such a value is copy
it, pass it to/from functions, store it, etc. It certainly isn't going to
try to treat it as a garbage collection root, or consider moving the object
it points at.
--
Alastair Reid