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:
Mark Thom
2025-02-16 22:47:49 -08:00
committed by GitHub
3 changed files with 42 additions and 1 deletions

View File

@@ -271,6 +271,11 @@ impl Machine {
.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(
&mut self,
module_name: Atom,
@@ -279,6 +284,8 @@ impl Machine {
if let Some(module) = self.indices.modules.get(&module_name) {
if let Some(code_index) = module.code_dir.get(&key) {
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.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));
}
}