yallop / ocaml-ctypes

Library for binding to C libraries using pure OCaml
MIT License
363 stars 95 forks source link

Strange error while calling a C vararg function #756

Closed vrotaru closed 8 months ago

vrotaru commented 9 months ago

Here is the relevant part of the code

let gobject_library = Dl.dlopen ~flags:[Dl.RTLD_NOW] ~filename:"libgobject-2.0.so"
let example_application_preferences_new wobj =
  Gc.compact ();
  Foreign.foreign ~from:gobject_library "g_object_new"
    Ctypes.(ulong @-> string @-> ptr void @-> string @-> bool @-> ptr void @-> returning (ptr void))
    !example_application_preferences_type
    "transient-for" wobj
    "use-header-bar" true
    Ctypes.null

And here is the error:

Fatal error: exception Ctypes_ffi_stubs.CallToExpiredClosure
Raised by primitive operation at Ctypes_ffi.Make.invoke.(fun) in file "src/ctypes-foreign/ctypes_ffi.ml", line 113, characters 18-171
Called from Hello.example_application_startup.(fun) in file "hello.ml", line 221, characters 18-65
Called from Ctypes_ffi.Make.box_function.(fun) in file "src/ctypes-foreign/ctypes_ffi.ml", line 151, characters 16-144
Called from Ctypes_ffi.Make.invoke.(fun) in file "src/ctypes-foreign/ctypes_ffi.ml", line 113, characters 18-171
Called from Ctypes_ffi.Make.invoke.(fun) in file "src/ctypes-foreign/ctypes_ffi.ml", line 113, characters 18-171
Called from Hello in file "hello.ml", line 459, characters 15-33

And if I remove the Gc.compact (); line it works as expected and creates the preferences dialog. This one: Screenshot from 2023-10-03 10-00-19

I have looked at the "src/ctypes-foreign/ctypes_ffi.ml", line 151, characters 16-144 and it tries to de-reference a weak ref and it fails. That's OK.

What I do not understand where is the closure which is GC-ed away. And why.

PS. If any more context is needed, I'll be glad to oblige. Unfortunately I do not have a small self-containing example, reproducing it, or I would have attached it.

And Gc.compact () does not seem to have any effect on a similar vararg invocation of printf

yallop commented 8 months ago

I don't know whether it's related to the problem you're seeing, but calling variadic functions is likely to work better using stub generation than via the Foreign interface, since the C compiler can see the prototype at the point of the call. If you can, I recommend switching to stub generation.

vrotaru commented 8 months ago

Sorry for the confusion, the error was on my part.

There is a protocol is for object extension and as part of this protocol one has to supply a class_init function and an instance_init functions to the C runtime. I was providing those as closure, and Gc.compact () war doing what it was supposed to do.

I'm closing the issue.