Stéphane Glondu wrote:
> I can see that cairo_surface_t finalizer is always called when expected.
> ml_cairo_image_surface_create_for_data does register a global root, but
> caml_{register/remove}_global_root calls are always paired.
The bug scenario in fact involves two custom blocks - cairo_surface_t and bigarray.

The cairo_surface_t finalizer (ml_final_cairo_surface_t) is called correctly, but the
bigarray finalizer (caml_ba_finalize) is not called at all. The bigarray value somehow
disappears from the OCaml heap. The corresponding bigarray data on the C heap is not reclaimed.

I've found a thread from caml-list archives which suggests that calling
caml_{register/remove}_global_root from custom block finalizers might not be safe:

http://www.mail-archive.com/caml-list@yquem.inria.fr/msg03746.html
I've tried to relate the bug to the OCaml GC. My current idea is as follows:
The custom block
- is always allocated in the major heap
- is reclaimed and finalizer is called in sweep_slice() in major_gc.c
- is also reclaimed in caml_compact_heap() in compact.c - and finalizer is not called!
compact.c:
310 /* No pointers to the header and no infix header:
311 the object was free. */
312 *p = Make_header (Wosize_ehd (q), Tag_ehd (q), Caml_blue);
313 p += Whsize_ehd (q);

The custom block is manipulated in this part of the GC code (confirmed by inserting a tag
check here, and running bug.ml through the modified ocamlrun). Moreover, the bug does not
appear if Gc.compact is replaced by Gc.full_major.