robur-coop / miou

A simple scheduler for OCaml 5
https://docs.osau.re/miou/index.html
MIT License
90 stars 6 forks source link

Backtraces from exception raised inside Miou.call_cc do not give the origin of exception #19

Open kit-ty-kate opened 4 months ago

kit-ty-kate commented 4 months ago
$ CAMLRUNPARAM=b dune exec -- ./test.exe
Fatal error: exception Failure("test")
Raised at Stdlib.failwith in file "stdlib.ml", line 29, characters 17-33
Re-raised at Miou.await_exn in file "lib/miou.ml", line 1027, characters 23-59
Re-raised at Miou.run in file "lib/miou.ml", line 1376, characters 23-59
Called from Miou_unix.run in file "lib/miou_unix.ml" (inlined), line 351, characters 25-56
Called from Dune__exe__Test in file "test.ml", lines 5-7, characters 2-19
$ cat test.ml
let raise_something () =
  failwith "test"

let () =
  Miou_unix.run @@ fun () ->
  let pr = Miou.call_cc (fun () -> raise_something ()) in
  Miou.await_exn pr
$ cat dune
(executable (name test) (libraries miou.unix))
$ cat dune-project
(lang dune 2.0)
dinosaure commented 4 months ago

You example is unfortunately a bit hard because raise_something is inlined. A solution for your specific case is explained here. So I write this code to show up the Miou's behavior:

$ cat >main.ml <<EOF
external reraise : exn -> 'a = "%reraise"

let[@inline never] id x = x
let[@inline never] raise_something () = failwith "test"
let[@inline never] raise_something () = id (raise_something ())

let () =
  let open Effect.Shallow in
  let retc = Fun.id in
  let exnc = reraise in
  let effc : type c. c Effect.t -> ((c, 'r) continuation -> 'r) option = fun _ -> None in
  let fiber = fiber raise_something in
  Format.printf "effect\n%!";
  match continue_with fiber () { retc; exnc; effc; } with
  | () -> ()
  | exception exn ->
    let bt = Printexc.get_raw_backtrace () in
    Printexc.print_raw_backtrace stdout bt

let () =
  Format.printf "pure\n%!";
  match raise_something () with
  | () -> ()
  | exception exn ->
    let bt = Printexc.get_raw_backtrace () in
    Printexc.print_raw_backtrace stdout bt

let () =
  Format.printf "miou\n%!";
  try Miou.run @@ fun () ->
      let prm = Miou.call_cc raise_something in
      Miou.await_exn prm
  with exn ->
    let bt = Printexc.get_raw_backtrace () in
    Printexc.print_raw_backtrace stdout bt
EOF
$ ocamlfind opt -g -linkpkg -package miou,miou.unix main.ml
$ OCAMLRUNPARAM=b ./a.out                                  
effect
Raised at Stdlib.failwith in file "stdlib.ml", line 29, characters 17-33
Called from Main.raise_something in file "main.ml", line 5, characters 43-63
Re-raised at Main in file "main.ml", line 10, characters 13-20
Called from Main in file "main.ml", line 14, characters 8-52
pure
Raised at Stdlib.failwith in file "stdlib.ml", line 29, characters 17-33
Called from Main.raise_something in file "main.ml", line 5, characters 43-63
Called from Main in file "main.ml", line 22, characters 8-26
miou
Raised at Stdlib.failwith in file "stdlib.ml", line 29, characters 17-33
Called from Main.raise_something in file "main.ml", line 5, characters 43-63
Re-raised at Miou.await_exn in file "lib/miou.ml", line 1027, characters 23-59
Re-raised at Miou.run in file "lib/miou.ml", line 1376, characters 23-59
Called from Main in file "main.ml", line 30, characters 6-100

So Miou (the current main version) does some reraise but keep the source along the backtrace (we can see "main.ml", line 5). I think, if you really want to take into account raise_something, the issue is more related to ocaml than miou.