[Haskell-cafe] FFI nested structs - malloc - free

Michael Steele mikesteele81 at gmail.com
Tue May 5 16:10:32 UTC 2015


Michael,

It looks like memory cleanup is being ignored in the example you linked to.
newCString and mallocArray do not automatically free memory.

When building nested structures simply in order to pass them to a few C
functions, I like to use with* and alloca* functions whenever possible.

The following (untested) example temporarily marshals a C structure
containing 2 pointers to null-terminated strings, and passes that to a
supplied action. 4-byte pointers and ints are assumed:

> data Person = Person String String Int
> withPerson :: Person -> (Ptr Person -> IO r) -> IO r
> withPerson (Person fn ln age) f =
>     -- Haskell's layout rules allow you to line these all up vertically.
>     -- Just place all your allocations before the first 'do'.
>     withCString fn $ \pfn ->
>     withCString ln $ \pln ->
>     allocaBytes 12 $ \ptr -> do
>     pokeByteOff ptr 0 pfn
>     pokeByteOff ptr 4 pln
>     pokeByteOff ptr 8 age
>     f ptr

In cases where you can't know ahead of time when the memory should be
freed, you an use ForeignPtr. I think Real World Haskell gives an example
of a nested structure marshaled in this way. By storing the ForeignPtr in a
data object that gets carried around, you can guarantee that finalizes get
called by the garbage collector only after you are done using them.

I hope that helps.

-- Michael Steele

On Tue, May 5, 2015 at 6:22 AM, Michael Jones <mike at proclivis.com> wrote:

> Alexey,
>
> That is an interesting insight. I suppose there are C API like that.
>
> In my case, the FFI calls ioctl, which calls i2cdev_ioctl, which calls
> i2cdev_ioctl_rdwr.
>
> The only function that can assume anything about the structure is
> i2cdev_ioctl_rdwr, which as you can see below copies the data, but does not
> free it.
>
> So in this particular case, I need the FFI to free it.
>
> On the other hand, I could write a wrapper in C that frees the structure
> if that is the way FFI is supposed to be used.
>
> Does anyone know if there is a FFI solution that would not require a
> wrapper?
>
> Mike
>
> static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
>                 unsigned long arg)
> {
>         struct i2c_rdwr_ioctl_data rdwr_arg;
>         struct i2c_msg *rdwr_pa;
>         u8 __user **data_ptrs;
>         int i, res;
>
>         if (copy_from_user(&rdwr_arg,
>                            (struct i2c_rdwr_ioctl_data __user *)arg,
>                            sizeof(rdwr_arg)))
>                 return -EFAULT;
>
>
>
> On May 4, 2015, at 10:40 PM, Alexey Shmalko <rasen.dubi at gmail.com> wrote:
>
> > Hi!
> >
> > Disclaimer: I haven't worked much with FFI, so I'd like someone
> > confirmed my words.
> >
> > Seems that allocated memory in your example is supposed to be freed
> > from inside C. It's not a memory leak.
> >
> > If I understand correctly documentation [1], malloc/free are just a
> > simple wrappers around C's malloc/free. It's mallocForeignPtr that
> > sets finalizer.
> >
> > Best regards,
> > Alexey Shmalko
> >
> > [1]:
> https://downloads.haskell.org/~ghc/7.8.3/docs/html/users_guide/ffi-ghc.html
> >
> > On Tue, May 5, 2015 at 6:45 AM, Proclivis <mike at proclivis.com> wrote:
> >> I should have mentioned GHC 7.8.3 Ubuntu 64bit
> >>
> >> Sent from my iPad
> >>
> >>> On May 4, 2015, at 9:42 PM, Proclivis <mike at proclivis.com> wrote:
> >>>
> >>> FFI Gurus,
> >>>
> >>> I created a c2hs FFI of a nested C structure, where struct A has a
> pointer to a struct B. To do so, I used a malloc, but I am unsure if the
> memory will be freed when the resulting Ptr is freed.
> >>>
> >>> The example at this link uses the same technique, so it will serve as
> an example.
> >>>
> >>>
> https://github.com/ifesdjeen/haskell-ffi-tutorial/blob/master/src/Example.hsc
> >>>
> >>> Line 48 and 51 do the malloc and assign the pointer in the struct,
> from inside a Storable poke implementation.
> >>>
> >>> But, there is no explicit free, nor a finalizer.
> >>>
> >>> Will the memory be freed when the Ptr of the Storable is freed?
> >>>
> >>> If it is, it implies that some magic keeps track of mallocs inside a
> poke, and creates finalizers. Or, this example leaks. If it leaks, how do I
> create a finalizer from inside a poke implementation?
> >>>
> >>> Mike
> >>>
> >>> _______________________________________________
> >>> Haskell-Cafe mailing list
> >>> Haskell-Cafe at haskell.org
> >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> >>
> >> _______________________________________________
> >> Haskell-Cafe mailing list
> >> Haskell-Cafe at haskell.org
> >> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>



-- 
-- Michael Steele
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20150505/4360b2e5/attachment.html>


More information about the Haskell-Cafe mailing list