Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stack overflow does not have exception backtrace #7206

Closed
vicuna opened this issue Apr 1, 2016 · 11 comments
Closed

Stack overflow does not have exception backtrace #7206

vicuna opened this issue Apr 1, 2016 · 11 comments

Comments

@vicuna
Copy link

vicuna commented Apr 1, 2016

Original bug ID: 7206
Reporter: william
Status: acknowledged (set by @xavierleroy on 2016-12-03T19:00:41Z)
Resolution: open
Priority: low
Severity: feature
Category: runtime system and C interface
Monitored by: @oandrieu

Bug description

there is no debug indication on what could generate the exception, which can be very annoying, especially when you are running long computations that generate this kind of errors...

Steps to reproduce

let rec make_n n = if n = 0 then [] else n::(make_n (n-1));;
make_n 262066

@vicuna
Copy link
Author

vicuna commented Apr 1, 2016

Comment author: pcouderc

Actually the backtrace is available when compiling in bytecode (mk.ml contains your example):
$ ocamlc -g mk.ml
$ export OCAMLRUNPARAM="-b"; ./a.out
Fatal error: exception Stack_overflow
Raised by primitive operation at file "mk.ml", line 1, characters 44-58
Called from file "mk.ml", line 1, characters 44-58
Called from file "mk.ml", line 1, characters 44-58
Called from file "mk.ml", line 1, characters 44-58
Called from file "mk.ml", line 1, characters 44-58
Called from file "mk.ml", line 1, characters 44-58
Called from file "mk.ml", line 1, characters 44-58
Called from file "mk.ml", line 1, characters 44-58
...

@vicuna
Copy link
Author

vicuna commented Apr 1, 2016

Comment author: pcouderc

It also works in native code actually:

let rec make_n n = if n = 0 then [] else n::(make_n (n-1));;
let _ =
Printexc.record_backtrace true;
make_n 26206600

$ ocamlopt -g mk.ml
$ ./a.out
Fatal error: exception Stack_overflow
Raised by primitive operation at file "mk.ml", line 1, characters 44-58

In any case, you need to compile with debug informations ("-g") and record the backtraces ('Printexc.record_backtrace true' at the beginning of your program for example) to get the backtrace, for any exception it is the only way to get the location of where it happened.

@vicuna
Copy link
Author

vicuna commented Apr 1, 2016

Comment author: william

interesting, because with this example (that I first tested with toplevel), I get no error. With a higher number, I get actualy this output :
./a.out
Fatal error: exception Stack_overflow
Raised by primitive operation at file "pervasives.ml", line 490, characters 8-63

=> no backtrace from mk.ml

I don't know how it happened, but in a previous atempt I got:
./mk.native
Fatal error: exception Stack_overflow
Called from file "list.ml", line 55, characters 32-39
Called from file "list.ml", line 55, characters 32-39
Called from file "list.ml", line 55, characters 32-39
Called from file "list.ml", line 55, characters 32-39
[...]

Also, in my real program, I got a similar but different message :
Fatal error: exception Stack overflow
(there is no "_" in the message)

I guess it is not easy to just specify the line (once and only once) that generates the problem.

@vicuna
Copy link
Author

vicuna commented Apr 1, 2016

Comment author: william

ah ok, with Printexc.record_backtrace true, I get like you :
Fatal error: exception Stack overflow
Raised by primitive operation at file "mk.ml", line 1, characters 0-30

@vicuna
Copy link
Author

vicuna commented Apr 1, 2016

Comment author: william

==> ok, so I see to things :

  • first, Printexc.record_backtrace generates a different behaviour than when only using export OCAMLRUNPARAM='b'

  • second, I got two different kinds of exception. The first one, more typical : "Fatal error: exception Stack overflow" which is able to raise the backtrace. And the second one : "Fatal error: exception Stack overflow" that does not generate the backtrace. Unfortunately I don't have time to slice down this error.

@vicuna
Copy link
Author

vicuna commented Apr 1, 2016

Comment author: pcouderc

Also, in my real program, I got a similar but different message :
Fatal error: exception Stack overflow
(there is no "_" in the message)

My bad, I've been a little bit lazy and actually truncated my first backtrace (bytecode version) to remove all the "Called from..." lines, since they were not outputed for the native version, instead of properly copying the result of the program I compiled in native code. It is still the 'Stack_overflow' exception though, but printed differently (for what reason?).

You're right, in native version it does not give you the complete backtrace (only the place where the exception was raised).

@vicuna
Copy link
Author

vicuna commented Apr 1, 2016

Comment author: william

ah, typo in my previous message. The correct one is here :

  • First, Printexc.record_backtrace generates a different behaviour than when only using export OCAMLRUNPARAM='b'

  • Second, I got two different kinds of exception. The first one, more typical : "Fatal error: exception Stack_overflow" which is able to raise the backtrace. And the second one : "Fatal error: exception Stack overflow" (without "_") that does not generate the backtrace. Unfortunately I don't have time to slice down this error.

@vicuna
Copy link
Author

vicuna commented Apr 1, 2016

Comment author: william

ahh, my message is still not correct.

Here is my last version :

let rec make_n n = if n = 0 then [] else n::(make_n (n-1));;
let _ =
Printexc.record_backtrace true;
make_n 26206600

(export OCAMLRUNPARAM='b')
ocamlopt -g mk.ml
./a.out

** with no Printexc.record, and with "ocamlopt mk.ml" :
Fatal error: exception Stack_overflow
Raised by primitive operation at file "pervasives.ml", line 490, characters 8-63
=> backtrace even with no option "-g" ?

** with no Printexc.record, and with "ocamlopt -g mk.ml":
Fatal error: exception Stack_overflow
Raised by primitive operation at file "pervasives.ml", line 490, characters 8-63
=> backtrace not available from mk.ml file ?

** with Printexc.record, and with "ocamlopt mk.ml" :
Fatal error: exception Stack overflow
=> no backtrace ?

** with Printexc.record and with "ocamlopt -g mk.ml" :
Fatal error: exception Stack overflow
Raised by primitive operation at file "mk.ml", line 3, characters 2-32
=> Printexc.record_backtrace generates a different behaviour than when only using export OCAMLRUNPARAM='b'

@vicuna
Copy link
Author

vicuna commented Nov 29, 2016

Comment author: @oandrieu

getting a bactktrace in case of Stack overflow is a bit inaccurate because the mechanism relies on some C values to unwind the stack: caml_bottom_of_stack and caml_last_return_address. When a regular exception is raised or when it calls a C function, OCaml updates these values. But in case of a stack overflow, control is brutally yanked away from the OCaml code, so when the exception is raised, the backtrace mechanism uses the previous values of these C variables, that is the last time the program entered the runtime.

That's why the backtrace points at Pervasives here: the last 'external' call in the program.

Calling Printexc.record_backtrace has two effects:

  • it's a C call, so it update those C values for stack unwinding and alters the result you'll get for the backtrace
  • it links in Printexc in your program, which changes the default uncaught exception handler ; this explains the difference in the string ("Stack_overflow" is the default C handler, "Stack overflow" if the OCaml handler in Printexc).

** with no Printexc.record, and with "ocamlopt mk.ml" :
=> backtrace even with no option "-g" ?
yes, because Pervasives is compiled with -g

** with no Printexc.record, and with "ocamlopt -g mk.ml":
=> backtrace not available from mk.ml file ?
your program is too simple, it had no occasion to enter the runtime in this module before the stack overflow

** with Printexc.record, and with "ocamlopt mk.ml" :
=> no backtrace ?
yes Mk is not compiled with -g, so no backtrace

** with Printexc.record and with "ocamlopt -g mk.ml" :
=> Printexc.record_backtrace generates a different behaviour than when only using export OCAMLRUNPARAM='b'
you get a backtrace in Mk, but it points to the last time the program entered the runtime, which is this C call to record_backtrace.

@vicuna
Copy link
Author

vicuna commented Dec 3, 2016

Comment author: @xavierleroy

This is a known limitation. The way stack overflows are caught in natively-compiled programs is a lot of black magic, and not even guaranteed to always turn the condition into a Stack_overflow exception. Don't expect a solution any time soon.

oandrieu added a commit to oandrieu/ocaml that referenced this issue Oct 22, 2019
when OCaml is configured --with-frame-pointers (so, only on AMD64/Linux),
we can use it in the stack overflow handler to determine the
last_return_address and bottom_of_stack values, which enables correct
backtrace stashing for the Stack overflow exception.

addresses partially ocaml#7206
oandrieu added a commit to oandrieu/ocaml that referenced this issue Oct 25, 2019
when OCaml is configured --with-frame-pointers (so, only on AMD64/Linux),
we can use it in the stack overflow handler to determine the
last_return_address and bottom_of_stack values, which enables correct
backtrace stashing for the Stack overflow exception.

addresses partially ocaml#7206
@github-actions
Copy link

github-actions bot commented May 9, 2020

This issue has been open one year with no activity. Consequently, it is being marked with the "stale" label. What this means is that the issue will be automatically closed in 30 days unless more comments are added or the "stale" label is removed. Comments that provide new information on the issue are especially welcome: is it still reproducible? did it appear in other contexts? how critical is it? etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant