OCaml and backtraces

Why OCaml 4.07.1 gives almost identical backtrace in case of exception?

ERROR: Writing file from Bigarray failed!
ERROR: (Unix.Unix_error "Permission denied" map_file "") Raised at file "format.ml" (inlined), line 242, characters 35-52
Called from file "format.ml", line 469, characters 8-33
Called from file "format.ml", line 484, characters 6-24

It happens in this function and see the code I use to show the backtrace:

let file_write_bigarray ~path ?(pos=0L) ~data =
    let data_size = Bigarray.Array1.dim data in
    try
        let fd = Unix.openfile path ~mode:[Unix.O_WRONLY;Unix.O_CREAT] in
        let ba = Bigarray.array1_of_genarray (Caml.Unix.map_file fd
            ~pos Bigarray.char
            Bigarray.c_layout true [|data_size|])
        in
        Bigarray.Array1.blit data ba;
        Unix.close fd
    with
    | e ->
        Lwt_io.printf "ERROR: Writing file from Bigarray failed!\n" |> ignore;
        let msg = Exn.to_string e
        and stack = Printexc.get_backtrace () in
        Lwt_io.printf "ERROR: %s %s\n" msg stack |> ignore

Ok, the exception string is OK, but why backtrace shows format.ml instead of the actual file name?

Oh, nevermind, found:

1 Like

I added (flags (-g)) (link_flags (... -g)) in my dune file and ran the binary with OCAMLRUNPARAM=b set, but backtrace is still the same.

The problem is that Format catches and reraises the exception polluting the backtrace along the way. This is behavior should be fixed in 4.08.0 where Format uses raise_notrace to avoid this very issue.

5 Likes

As an aside, dune already defaults to compiling with -g (source). Also, OCAMLRUNPARAM is only evaluated by the bytecode versions, not the native binary.

Yes, I figured later that dune builds with symbols by default. Good to know the environment variable doesn’t work in the native mode.

I just discussed this issue with XVilka on IRC and wish to set the record for those finding this page by google :slight_smile: , and it seems the key here is that Printexc.get_backtrace () should be the first thing done in the exception handler. Exn.to_string clobbers this value.

Also a small correction: OCAMLRUNPARAM does work with native binaries, as long as they have been compiled with -g. Sometimes its scope may be affected by inlining, but in general it’s very useful.

1 Like