How to debug a segfault with OCaml 5.1

Hello everyone,

I’m trying to upgrade the OCaml version we are using to compile my program.
My program initially worked with OCaml 4.14.1.
When I upgraded to OCaml 5.0 everything worked well without modifying the code, but with OCaml 5.1 I get a segfault during the initialization phase of my program. The segfault happens when the caml_darken function of the marjor GC is called.

gdb shows the following backtrace

(gdb) bt
#0  0x0000555556234c18 in caml_darken (ignored=<optimized out>, v=93825007432256, state=0x5555569ce1a0) at runtime/major_gc.c:1070
#1  caml_darken (state=0x5555569ce1a0, v=<optimized out>, ignored=<optimized out>) at runtime/major_gc.c:1052
#2  0x000055555622c6fb in scan_native_globals (fdata=0x5555569ce1a0, f=0x555556234bc0 <caml_darken>) at runtime/globroots.c:205
#3  caml_scan_global_roots (f=f@entry=0x555556234bc0 <caml_darken>, fdata=fdata@entry=0x5555569ce1a0) at runtime/globroots.c:241
#4  0x00005555562345ea in cycle_all_domains_callback (domain=domain@entry=0x5555569ce1a0, unused=unused@entry=0x0, participating_count=<optimized out>, participating=participating@entry=0x5555569c5f20 <stw_request+64>) at runtime/major_gc.c:1346
#5  0x0000555556224d08 in caml_try_run_on_all_domains_with_spin_work (sync=sync@entry=1, handler=handler@entry=0x555556234490 <cycle_all_domains_callback>, data=data@entry=0x0, leader_setup=leader_setup@entry=0x0, enter_spin_callback=enter_spin_callback@entry=0x0, 
    enter_spin_data=enter_spin_data@entry=0x0) at runtime/domain.c:1480
#6  0x0000555556224dfd in caml_try_run_on_all_domains (handler=handler@entry=0x555556234490 <cycle_all_domains_callback>, data=data@entry=0x0, leader_setup=leader_setup@entry=0x0) at runtime/domain.c:1502
#7  0x000055555623600e in major_collection_slice (howmuch=<optimized out>, participant_count=participant_count@entry=0, barrier_participants=barrier_participants@entry=0x0, mode=mode@entry=Slice_interruptible) at runtime/major_gc.c:1691
#8  0x00005555562361d6 in caml_major_collection_slice (howmuch=howmuch@entry=-1) at runtime/major_gc.c:1708
#9  0x0000555556224665 in caml_poll_gc_work () at runtime/domain.c:1631
#10 0x000055555623e4bc in caml_do_pending_actions_exn () at runtime/signals.c:308
#11 0x000055555623997d in caml_alloc_small_dispatch (dom_st=0x5555569ce1a0, wosize=<optimized out>, flags=<optimized out>, nallocs=<optimized out>, encoded_alloc_lens=<optimized out>) at runtime/minor_gc.c:816
#12 <signal handler called>
#13 0x0000555555b5e786 in camlKernel__FCSet.Make_1302 () at kernel/
#14 0x0000555555b5decb in camlKernel__FCSet.fun_2297 () at kernel/
#15 0x0000555555b8f4d8 in camlKernel__Datatype.With_collections_8414 () at kernel/
#16 0x0000555555b8fe2f in camlKernel__Datatype.fun_59589 () at kernel/
#17 0x0000555555bd6fda in camlKernel__Cil_datatype.entry () at kernel/
#18 0x0000555555b4b8eb in caml_program ()
#19 <signal handler called>
#20 0x0000555556245176 in caml_startup_common (pooling=<optimized out>, argv=0x7fffffffd6b8) at runtime/startup_nat.c:132
#21 caml_startup_common (argv=0x7fffffffd6b8, pooling=<optimized out>) at runtime/startup_nat.c:88
#22 0x00005555562451ef in caml_startup_exn (argv=<optimized out>) at runtime/startup_nat.c:139
#23 caml_startup (argv=<optimized out>) at runtime/startup_nat.c:144
#24 caml_main (argv=<optimized out>) at runtime/startup_nat.c:151
#25 0x0000555555b4a5b2 in main (argc=<optimized out>, argv=<optimized out>) at runtime/main.c:37

Do you have some ideas to debug the program and identify more clearly the problem, or the value that leads to the segfault?

Do you have C bindings in your code? One thing to watch out for is that OCaml 5 does not support naked pointers. Code using naked pointers in OCaml 4 should be updated for OCaml 5. There is a naked pointer checker available as an opam compiler switch on OCaml 4 to identify naked pointers in your code.

If not, this may be a bug in the compiler. Please can you make an issue on OCaml GitHub repo with a reproduction case.

To add to @kayceesrk’s good suggestion, there is an unknown number (but AFAIR greater than a dozen) of packages on opam that use naked pointers but have been marked as compatible with OCaml 5, and which show up as green in the CI.

I posted below a simple method to see if one idiom which creates naked pointers is present inside your dependencies (adapted for opam, but it adapts to other packaging method):

The usefulness of the compile-time option to detect possible naked pointers at runtime (badly named nnp “checker”) seems relative.


Given that it was working on 5.0, I’d be tempted to try to bisect initially instead (which is how Domain.DLS.get data corruption · Issue #12515 · ocaml/ocaml · GitHub got solved).

Is your program still building correctly with 5.0 - in particular, are the dependencies definitely identical when you compile with 5.1 (same versions of all opam packages). Is the code public?


Thank you everyone for your help.
I finally tried to install OCaml 4.14.1 with the nnp-checker. Unfortunately it didn’t find anything when I ran my program on different test cases.

I investigated more by looking at all the occurrences of Obj in my code. When I removed one of its occurences everything worked again with OCaml 5.1. This occurence was Obj.field (Obj.repr 0L) 0.

I do not really understand what is wrong with this code and why it would create a naked pointer. Thus I did some tests to try to understand what can happen in my case. I copy paste the results of my experimentation with OCaml 5.1

$ ocaml
OCaml version 5.1.0
Enter #help;; for help.

# Obj.is_block (Obj.repr 0L);;
- : bool = true
# Obj.tag (Obj.repr 0L);;
- : int = 255
# Obj.size (Obj.repr 0L);; 
- : int = 2
# Obj.field (Obj.repr 0L) 0;;
Erreur de segmentation (core dumped)

The toplevel results are the same with OCaml 5.0 even if my code doesn’t crash in this case. Did I missed some changes in the representation of the Int64 in Ocaml 5?

Is your program still building correctly with 5.0 - in particular, are the dependencies definitely identical when you compile with 5.1 (same versions of all opam packages). Is the code public?

Unfortunately my code is not public and I am not sure to have enough time to bisect…

The value 0L is an int64 value, which is represented by a Custom_tag object (the tag being 255).

# Obj.custom_tag;;
- : int = 255

The first field of the custom tag object is a pointer to a C structure holding the custom operations for that type. See

The code Obj.field (Obj.repr 0L) 0 gets this first field. The result of this expression is indeed a naked pointer (pointer outside of the OCaml heap). The OCaml 5 top-level tries to print it and crashes. OCaml 4 is aware of naked pointers and just prints <abstr> instead.

Not sure what the code Obj.field (Obj.repr 0L) 0 is supposed to do in your original code. Depending on what you were trying to do, there are easy ways around this.