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

Michael Jones mike at proclivis.com
Mon May 11 15:25:34 UTC 2015


GCC, well that is funny. The iPad looks like it made a spelling fix. Guess I have to reread what I type before sending :-)

I’ll go off and try to implement from this and see how it goes. At least the principles are clear. I just have to look at how to do this in the context of a Storable instance.

Thanks


On May 11, 2015, at 12:47 AM, Alexey Shmalko <rasen.dubi at gmail.com> wrote:

> 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/49ff4eb9/attachment.html>


More information about the Haskell-Cafe mailing list