如何在OCaml中获取完整的未截断的堆栈跟踪,以便在堆栈溢出后进行调试?

4

OCaml栈追踪在栈溢出时会被截断。例如,下面的程序会产生如下所示的栈追踪:

let rec f0 () = 1 + f1 ()
    and f1 () = 1 + f2 ()
    and f2 () = 1 + f3 ()
    and f3 () = 1 + f4 ()
    and f4 () = 1 + f5 ()
    and f5 () = 1 + f5 ()

let _ =
  Printexc.record_backtrace true;
  f0 ()

Fatal error: exception Stack overflow
Raised by primitive operation at file "stackoverflow.ml", line 6, characters 20-25
Called from file "stackoverflow.ml", line 6, characters 20-25
…
Called from file "stackoverflow.ml", line 6, characters 20-25

与错误不是堆栈溢出时的堆栈跟踪相比(将最后一个f5()更改为failwith "Oops"),请查看以下内容:
Fatal error: exception Failure("Oops")
Raised at file "pervasives.ml", line 30, characters 22-33
Called from file "stackoverflow.ml", line 6, characters 20-35
Called from file "stackoverflow.ml", line 5, characters 20-25
Called from file "stackoverflow.ml", line 4, characters 20-25
Called from file "stackoverflow.ml", line 3, characters 20-25
Called from file "stackoverflow.ml", line 2, characters 20-25
Called from file "stackoverflow.ml", line 1, characters 20-25
Called from file "stackoverflow.ml", line 10, characters 2-7

如何防止 OCaml 截断堆栈跟踪?
3个回答

4
当我重现您的结果时,我得到了1024行回溯,这个数字有些可疑。
实际上,我发现该库在byterun/caml/backtrace_prim.h中强制设定了最大回溯大小为1024。
#define BACKTRACE_BUFFER_SIZE 1024

如果您想要更大的回溯,可能需要构建一个新的标准库。

值得一提的是,我使用ocamlc进行了一个小测试,当溢出发生时(使用默认栈大小),我看到大约有262,000个活动堆栈帧。

(已使用OCaml 4.04的正确文件名进行编辑。)


2

您可以限制堆栈大小,以避免溢出回溯缓冲区,例如(使用字节码测试)

$ env OCAMLRUNPARAM=b,l=1000 ./test
[...]
Called from file "test.ml", line 6, characters 20-25
Called from file "test.ml", line 6, characters 20-25
Called from file "test.ml", line 5, characters 20-25
Called from file "test.ml", line 4, characters 20-25
Called from file "test.ml", line 3, characters 20-25
Called from file "test.ml", line 2, characters 20-25
Called from file "test.ml", line 1, characters 20-25
Called from file "test.ml", line 10, characters 2-7

2
您可以使用ocamldebug获取堆栈跟踪:
ocamlc stackoverflow.ml -o stackoverflow
ocamldebug stackoverflow

然后在ocamldebug中:
(ocd) run
 [...] 
 Uncaught exception: Stack_overflow
(ocd) backstep
(ocd) bt

你可能想在ocamlc中添加调试标志(-g),以便在调试器中执行额外的操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接