打印堆栈跟踪

Dan*_*ner 3 ocaml exception stack-trace

我有一个非常短的测试文件:

let print_backtrace () = try raise Not_found with
    Not_found -> Printexc.print_backtrace stdout;;

let f () = print_backtrace (); Printf.printf "this is to make f non-tail-recursive\n";;

f ();
Run Code Online (Sandbox Code Playgroud)

我编译并运行:

% ocamlc -g test.ml      
% OCAMLRUNPARAM=b ./a.out
Raised at file "test.ml", line 1, characters 35-44
this is to make f non-tail-recursive
Run Code Online (Sandbox Code Playgroud)

为什么没有f列在堆栈跟踪中?如何编写一个函数来打印它所调用位置的堆栈跟踪?

Jef*_*eld 6

文档Printexc.print_backtrace说:

回溯列出了引发最近引发的异常的程序位置以及通过函数调用传播的位置.

它实际上似乎正在做正确的事情.该异常尚未通过f传播回来.

如果我将呼叫转移到呼叫Printexc.print_backtrace之外f,我会看到完整的回溯.

$ cat test2.ml
let print_backtrace () = raise Not_found

let f () = let res = print_backtrace () in res ;;

try f () with Not_found -> Printexc.print_backtrace stdout
$ /usr/local/ocaml312/bin/ocamlc -g test2.ml
$ OCAMLRUNPARAM=b a.out 
Raised at file "test2.ml", line 1, characters 31-40
Called from file "test2.ml", line 3, characters 21-39
Called from file "test2.ml", line 5, characters 4-8
Run Code Online (Sandbox Code Playgroud)

  • 没有黑客攻击OCaml运行时,我没有看到一个很好的方法.也许在ocamldebug下运行?或者因为你似乎在某种Unix上运行,如果这只是为了快速排除故障,你可以fork()你的进程并在子进程中引发一个未捕获的异常(它将打印一个完整的堆栈跟踪),然后退出子进程并继续进行父进程.我在C年前做过这样的事情,它对我有用.但它很丑陋,可能会弄乱一些东西.如果您尝试这个(可能是个坏主意),请在子进程中调用_Exit()以避免刷新缓冲区.问候, (3认同)

Jef*_*eld 5

这是执行我建议的代码.如果可能的话,我建议使用ocamldebug,这段代码太棘手了.但是对于这个简单的例子,它适用于我的系统.

let print_backtrace () =
    match Unix.fork () with
    | 0 -> raise Not_found
    | pid -> let _ = Unix.waitpid [] pid in ()

let f () =
    begin
    print_backtrace ();
    Printf.printf "after the backtrace\n";
    end

;;

f ()
Run Code Online (Sandbox Code Playgroud)

这是一个测试运行.

$ /usr/local/ocaml312/bin/ocamlc unix.cma -g test3.ml
$ OCAMLRUNPARAM=b a.out
Fatal error: exception Not_found
Raised at file "test3.ml", line 3, characters 17-26
Called from file "test3.ml", line 8, characters 4-22
Called from file "test3.ml", line 14, characters 0-4
after the backtrace
Run Code Online (Sandbox Code Playgroud)

我意识到,由于未被捕获的异常,您实际上无法控制子进程的退出方式.这就是为什么这段代码太棘手了.如果它不适合你,请不要怪我,但我希望它确实有用.

我使用OCaml 3.12.0在Mac OS X 10.6.8上测试了代码.

最好的祝福,