If the OCaml code did not provide a close method, we would never call
close_wrapper, and then we ended up leaking the global root and handle.
---
plugins/ocaml/plugin.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/plugins/ocaml/plugin.c b/plugins/ocaml/plugin.c
index fe781f9af..a4671d6ed 100644
--- a/plugins/ocaml/plugin.c
+++ b/plugins/ocaml/plugin.c
@@ -76,6 +76,7 @@ constructor (void)
* nbdkit_plugin struct and return it from our own plugin_init
* function.
*/
+static void close_wrapper (void *h);
static void unload_wrapper (void);
static void free_strings (void);
static void remove_roots (void);
@@ -92,6 +93,10 @@ static struct nbdkit_plugin plugin = {
*/
.name = NULL,
+ /* We always call these, even if the OCaml code does not provide a
+ * callback.
+ */
+ .close = close_wrapper,
.unload = unload_wrapper,
};
@@ -345,6 +350,9 @@ open_wrapper (int readonly)
CAMLreturnT (void *, ret);
}
+/* We always have a close function, since we need to unregister the
+ * global root and free the handle.
+ */
static void
close_wrapper (void *h)
{
@@ -352,10 +360,12 @@ close_wrapper (void *h)
CAMLparam0 ();
CAMLlocal1 (rv);
- rv = caml_callback_exn (close_fn, *(value *) h);
- if (Is_exception_result (rv)) {
- nbdkit_error ("%s", caml_format_exception (Extract_exception (rv)));
- /*FALLTHROUGH*/
+ if (close_fn) {
+ rv = caml_callback_exn (close_fn, *(value *) h);
+ if (Is_exception_result (rv)) {
+ nbdkit_error ("%s", caml_format_exception (Extract_exception (rv)));
+ /*FALLTHROUGH*/
+ }
}
caml_remove_generational_global_root (h);
--
2.41.0