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

Proclivis mike at proclivis.com
Sun May 10 15:58:16 UTC 2015


Thanks guys,

I looks like there are basically 2 ways to do this:

1) Build a structure of ForeignPtr with finalizers that will be freed whenever the GCC feels like it
2) Nest allocations and the will free at the end of IO 

I noticed that in Real World Haskell the example of #1 has a ForeignPtr and ByteString in a data constructor, and both are bang noted as strict. Is this required before passing the data to a C-call to ensure it is evaluated or just a choice with the usual implications, such that with or without the evaluation of the C-call is well behaved?

Mike

Sent from my iPad

> On May 5, 2015, at 10:10 AM, Michael Steele <mikesteele81 at gmail.com> wrote:
> 
> 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/20150510/5e5d8fe8/attachment.html>


More information about the Haskell-Cafe mailing list