Fix MPR7253, exit behaviour in case of raising at_exit functions.#685
Fix MPR7253, exit behaviour in case of raising at_exit functions.#685dbuenzli wants to merge 1 commit intoocaml:trunkfrom
Conversation
Rather than building a closure that captures the list of [at_exit] functions to call at [exit] we explicitly store them in a mutable list in LIFO order. We change the [Pervasives.do_at_exit] function so that it sequentially pops one from the list before executing it. If the popped function raises, the general uncaught exception mecanism of [caml_main] kicks in. This eventually leads to the execution of [Printexc.handle_uncaught_exception'] which reports the uncaught exception and then calls [Pervasives.do_at_exit] to continue calling the remaining [at_exit] functions. The latter call is guarded to catch and report further exception raised by [at_exit] function in a loop, so that each uncaught expression in [at_exit] functions gets reported. This changes the semantics of the handler given to Printexc.set_uncaught_exception_handler. It used to be that handler would be called after all [at_exit] functions would have been called. This is no longer the case, it is called before any [at_exit] function that didn't get executed yet when the uncaught exception was raised.
| print_raw_backtrace stderr raw_backtrace; | ||
| eprintf "Fatal error in uncaught exception handler: exception %s\n" | ||
| (to_string exn'); | ||
| print_raw_backtrace stderr raw_backtrace'; |
There was a problem hiding this comment.
N.B. what you see here is a diff artefact I'm not changing the structure of this see the removed None case above.
|
Contrary to what I believed (and commented on the other PR), one can already have (There could also be a global mechanism to remember about the first or last non-0 code passed to |
Indeed and somehow I agree
The only problem is that we can't access Now I didn't dig too far into Will dig further... |
|
The "custom uncaught exception handlers" take a But there is already a "for system use only" section in Alternatively, one could collect all exceptions raised by at_exit hooks in a |
|
The issue is still open (e.g. in the original Mantis report), so I'm reading this discussion again. I cannot get an idea of which semantics (singular or plural) @dbuenzli , @alainfrisch , and the rest of us expect for an uncaught exception raised out of an |
|
From the documentation bits of this PR I think we want this:
|
|
|
This doesn't say what happens when the handler calls |
Ah ok you also wanted that story aswell. This is MPR7178 and discussed in GPR675 in particular for me this comment. So to sum up the full story for me would be for an
|
|
Thanks a lot @dbuenzli for having summarized the whole story. I'm still unsure where we go from there: is your semantics the one to be pursued or shall we look for something else? |
|
An easier one would be to have 1.+2. without the While I'm not so fond about systems who silently swallow errors as if nothing happened, one could argue that writing an exit handler requires care and thus mandate the programmer do the Regarding |
Fixes MPR7253
Rather than building a closure that captures the list of [at_exit]
functions to call at [exit] we explicitly store them in a mutable
list in LIFO order. We change the [Pervasives.do_at_exit] function
so that it sequentially pops one from the list before executing it.
If the popped function raises, the general uncaught exception mecanism
of [caml_main] kicks in. This eventually leads to the execution of
[Printexc.handle_uncaught_exception'] which reports the uncaught
exception and then calls [Pervasives.do_at_exit] to continue calling
the remaining [at_exit] functions. The latter call is guarded to catch
and report further exception raised by [at_exit] function in a loop,
so that each uncaught expression in [at_exit] functions gets reported.
This changes the semantics of the handler given to
Printexc.set_uncaught_exception_handler. It used to be that handler
would be called after all [at_exit] functions would have been called.
This is no longer the case, it is called before any [at_exit] function
that didn't get executed yet when the uncaught exception was raised.