Merge pull request #2817 from adri326/fix-2815-run_module_predicate-backtrack
Fix backtracking on the topmost predicate triggering UB in run_module_predicate
This commit is contained in:
@@ -568,7 +568,7 @@ impl Machine {
|
|||||||
self.run_module_predicate(atom!("loader"), (atom!("consult_stream"), 2));
|
self.run_module_predicate(atom!("loader"), (atom!("consult_stream"), 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate_stub_choice_point(&mut self) {
|
pub(crate) fn allocate_stub_choice_point(&mut self) {
|
||||||
// NOTE: create a choice point to terminate the dispatch_loop
|
// NOTE: create a choice point to terminate the dispatch_loop
|
||||||
// if an exception is thrown.
|
// if an exception is thrown.
|
||||||
|
|
||||||
|
|||||||
@@ -271,6 +271,11 @@ impl Machine {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Runs the predicate `key` in `module_name` until completion.
|
||||||
|
/// Siltently ignores failure, thrown errors and choice points.
|
||||||
|
///
|
||||||
|
/// Consider using [`Machine::run_query`] if you wish to handle
|
||||||
|
/// predicates that may fail, leave a choice point or throw.
|
||||||
pub(crate) fn run_module_predicate(
|
pub(crate) fn run_module_predicate(
|
||||||
&mut self,
|
&mut self,
|
||||||
module_name: Atom,
|
module_name: Atom,
|
||||||
@@ -279,6 +284,8 @@ impl Machine {
|
|||||||
if let Some(module) = self.indices.modules.get(&module_name) {
|
if let Some(module) = self.indices.modules.get(&module_name) {
|
||||||
if let Some(code_index) = module.code_dir.get(&key) {
|
if let Some(code_index) = module.code_dir.get(&key) {
|
||||||
let p = code_index.local().unwrap();
|
let p = code_index.local().unwrap();
|
||||||
|
// Leave a halting choice point to backtrack to in case the predicate fails or throws.
|
||||||
|
self.allocate_stub_choice_point();
|
||||||
|
|
||||||
self.machine_st.cp = BREAK_FROM_DISPATCH_LOOP_LOC;
|
self.machine_st.cp = BREAK_FROM_DISPATCH_LOOP_LOC;
|
||||||
self.machine_st.p = p;
|
self.machine_st.p = p;
|
||||||
@@ -1248,3 +1255,24 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::config::*;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore)]
|
||||||
|
fn test_run_module_predicate_throw() {
|
||||||
|
let mut machine = MachineBuilder::default()
|
||||||
|
.with_toplevel(
|
||||||
|
r#"
|
||||||
|
:- module('$toplevel', []).
|
||||||
|
repl :- throw(kaboom).
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
machine.run_module_predicate(atom!("$toplevel"), (atom!("repl"), 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,6 +29,19 @@ load_scryerrc :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
'$repl' :-
|
'$repl' :-
|
||||||
|
catch(
|
||||||
|
start_repl,
|
||||||
|
_,
|
||||||
|
% Something bad enough happened that the REPL itself threw an error.
|
||||||
|
% This can be caused by a broken user_output stream, so we cannot
|
||||||
|
% print an error.
|
||||||
|
%
|
||||||
|
% The best we can do now is halt with an error code,
|
||||||
|
% so that users can try to diagnose the issue:
|
||||||
|
halt(99)
|
||||||
|
).
|
||||||
|
|
||||||
|
start_repl :-
|
||||||
asserta('$toplevel':started),
|
asserta('$toplevel':started),
|
||||||
raw_argv(Args0),
|
raw_argv(Args0),
|
||||||
( append(Args1, ["--"|_], Args0) ->
|
( append(Args1, ["--"|_], Args0) ->
|
||||||
|
|||||||
Reference in New Issue
Block a user