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

Alexey Shmalko rasen.dubi at gmail.com
Mon May 11 06:47:18 UTC 2015


First note: it's not GCC, but Haskell's GC.

Second, I believe it's not necessary to put strict annotations because all
function parameters are evaluated before calling FFI function. It's just a
general good practice to make all data fields strict unless there are
reasons to do otherwise.

On Sun, May 10, 2015, 18:58 Proclivis <mike at proclivis.com> wrote:

> 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
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20150511/c555003c/attachment.html>


More information about the Haskell-Cafe mailing list