Binding glib into Crystal lang (GC issue)

453 views Asked by At

I am trying to bind some functions from glib into Crystal. I've done this and it works:

@[Link("glib-2.0")]
lib LibG
  fun g_utf8_strup(str : UInt8*, len : UInt32) : UInt8*
  fun g_utf8_strdown(str : UInt8*, len : UInt32) : UInt8*
end

However it introduces memory leak: the objects create with g_* functions will never be garbage collected.

Is it possible to make glib play well with Boehm GC in Crystal? Inspired by PCRE, I've tried this :

@[Link("glib-2.0")]
lib LibG
  # These 2 functions work perfectly
  fun g_utf8_strup(str : UInt8*, len : UInt32) : UInt8*
  fun g_utf8_strdown(str : UInt8*, len : UInt32) : UInt8*

  alias Malloc = LibC::SizeT -> Void*
  alias Free = Void* ->
  $g_malloc : Malloc
  $g_free : Free
end

# At this point happens segmentation fault
LibG.g_malloc = ->GC.malloc(LibC::SizeT)
LibG.g_free = ->GC.free(Void*)

In hope to override/redefine g_malloc and g_free functions. But it does not work out: it fails with segmentation fault.

Any ideas how to make glib play with GC? I've found somehow related question, but it haven't helped me: Garbage collection with glib?

Thanks in advence.

1

There are 1 answers

0
ptomato On BEST ANSWER

I would suggest using gobject-introspection for this purpose. It provides a .GIR file for each library which is a large XML file describing the API of each function, class, and method in the library, and how memory is handled for each input and output parameter. You can use it to dynamically generate bindings for libraries such as GLib.

It also provides an extensive unit testing library which you can use to check that your bindings are working correctly.

As for memory management, it seems like asking for trouble to override g_malloc and g_free. The equivalent way it's done in the gobject-introspection bindings for JavaScript is to always make sure that the JS environment owns the memory. For example, for strings being returned from a C function; if ownership of the returned string is given to the caller, then a JS string is created from the returned string (which copies the string) and the returned string is freed. If the library retains ownership of the returned string, then a JS string is created and the returned string is not freed. In both cases, the only memory in use is owned by the JS environment and is subject to JS's garbage collector.

GLib objects are another story, since they are reference-counted, and so the JS wrapper object can simply hold a reference to them; when the JS object is GC'd, it releases its reference and the C object is destroyed as well if no other JS object is holding on to it.