Fix backtracking on the topmost predicate triggering UB in run_module_predicate #2817
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #2815, see that issue for my investigation.
This is a one-line fix that I'm quite proud of :)
If the topmost query for
run_module_predicate
needs to backtrack, then before this commit, one of the following two things may happen:This can be seen by either calling
run_module_predicate
with a throwing predicate (encountering the second scenario) or a failing predicate (encountering the first scenario), or by running the following in the REPL, which triggers athrow/1
within the error handler, propagating it all the way up (and encountering the second scenario):Currently,
Stack
is not equipped with tools to detect this incorrect behavior, so it would instead try to read an OrFrame at offset 0, which triggers UB, since transmuting between AndFramePrelude and OrFramePrelude isn't legal.In practice, since
AndFramePrelude
is smaller, the later fields ofOrFramePrelude
would read from the cells following theAndFramePrelude
, and would contain nonsensical data, triggering the panic that led to my investigation in #2815 and that is fairly reliable to witness.Surprisingly, this wouldn't happen with
run_query
, which led me to look at how they operate differently. It turns out thatrun_query
inserts an OrFrame at offset 0, which covers both problematic scenarios.The fix is thus to simply add a call to
Machine::allocate_stub_choice_point
inrun_module_predicate
.There is only one detail left, which is that if the topmost predicate backtracks,
run_module_predicate
will exit while indicating success (when it really just failed).I chose to leave it at that and document it as such, as this is a behavior that is somewhat relied on, notably when loading a file with a syntax error (you wouldn't want that to cause a panic). Instead, I'm catching any "escaping" errors in
'$toplevel':'$repl'/0
to make it halt with error code99
.