add max arity checks at various stages (#1459)

This commit is contained in:
Mark Thom
2022-05-21 12:32:48 -06:00
parent b6f77f4e6f
commit 4d23542ef3
8 changed files with 48 additions and 65 deletions

View File

@@ -59,6 +59,7 @@ pub(crate) trait Allocator {
fn bindings_mut(&mut self) -> &mut AllocVarDict; fn bindings_mut(&mut self) -> &mut AllocVarDict;
fn take_bindings(self) -> AllocVarDict; fn take_bindings(self) -> AllocVarDict;
fn max_reg_allocated(&self) -> usize;
fn drain_var_data<'a>( fn drain_var_data<'a>(
&mut self, &mut self,

View File

@@ -865,6 +865,10 @@ impl<'b> CodeGenerator<'b> {
}; };
self.compile_query_line(term, term_loc, code, num_perm_vars, is_exposed); self.compile_query_line(term, term_loc, code, num_perm_vars, is_exposed);
if self.marker.max_reg_allocated() > MAX_ARITY {
return Err(CompilationError::from(ParserError::ExceededMaxArity));
}
} }
} }
} }
@@ -934,6 +938,10 @@ impl<'b> CodeGenerator<'b> {
let iter = FactIterator::from_rule_head_clause(args); let iter = FactIterator::from_rule_head_clause(args);
let mut fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head, false); let mut fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head, false);
if self.marker.max_reg_allocated() > MAX_ARITY {
return Err(CompilationError::from(ParserError::ExceededMaxArity));
}
let mut unsafe_var_marker = UnsafeVarMarker::new(); let mut unsafe_var_marker = UnsafeVarMarker::new();
if !fact.is_empty() { if !fact.is_empty() {
@@ -971,7 +979,7 @@ impl<'b> CodeGenerator<'b> {
UnsafeVarMarker::from_safe_vars(safe_vars) UnsafeVarMarker::from_safe_vars(safe_vars)
} }
pub(crate) fn compile_fact(&mut self, term: &Term) -> Code { pub(crate) fn compile_fact(&mut self, term: &Term) -> Result<Code, CompilationError> {
self.update_var_count(post_order_iter(term)); self.update_var_count(post_order_iter(term));
let mut vs = VariableFixtures::new(); let mut vs = VariableFixtures::new();
@@ -993,6 +1001,10 @@ impl<'b> CodeGenerator<'b> {
false, false,
); );
if self.marker.max_reg_allocated() > MAX_ARITY {
return Err(CompilationError::from(ParserError::ExceededMaxArity));
}
self.mark_unsafe_fact_vars(&mut compiled_fact); self.mark_unsafe_fact_vars(&mut compiled_fact);
if !compiled_fact.is_empty() { if !compiled_fact.is_empty() {
@@ -1001,7 +1013,7 @@ impl<'b> CodeGenerator<'b> {
} }
code.push(instr!("proceed")); code.push(instr!("proceed"));
code Ok(code)
} }
fn compile_query_line( fn compile_query_line(
@@ -1111,7 +1123,7 @@ impl<'b> CodeGenerator<'b> {
self.global_jmp_by_locs_offset = self.jmp_by_locs.len(); self.global_jmp_by_locs_offset = self.jmp_by_locs.len();
let clause_code = match clause { let clause_code = match clause {
&PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact), &PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact)?,
&PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?, &PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?,
}; };

View File

@@ -151,16 +151,13 @@ impl DebrayAllocator {
}; };
} }
fn alloc_reg_to_var<'a, Target>( fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
var: &String, var: &String,
lvl: Level, lvl: Level,
term_loc: GenContext, term_loc: GenContext,
target: &mut Vec<Instruction>, target: &mut Vec<Instruction>,
) -> usize ) -> usize {
where
Target: CompilationTarget<'a>,
{
match term_loc { match term_loc {
GenContext::Head => { GenContext::Head => {
if let Level::Shallow = lvl { if let Level::Shallow = lvl {
@@ -404,4 +401,9 @@ impl Allocator for DebrayAllocator {
self.arg_c = 1; self.arg_c = 1;
self.temp_lb = arity + 1; self.temp_lb = arity + 1;
} }
#[inline(always)]
fn max_reg_allocated(&self) -> usize {
std::cmp::max(self.temp_lb, self.arg_c)
}
} }

View File

@@ -52,7 +52,7 @@ pub(super) fn compile_relation(
match tl { match tl {
&TopLevel::Query(_) => Err(CompilationError::ExpectedRel), &TopLevel::Query(_) => Err(CompilationError::ExpectedRel),
&TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses), &TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses),
&TopLevel::Fact(ref fact, ..) => Ok(cg.compile_fact(fact)), &TopLevel::Fact(ref fact, ..) => cg.compile_fact(fact),
&TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule), &TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule),
} }
} }

View File

@@ -585,16 +585,11 @@ impl MachineError {
pub enum CompilationError { pub enum CompilationError {
Arithmetic(ArithmeticError), Arithmetic(ArithmeticError),
ParserError(ParserError), ParserError(ParserError),
// BadPendingByte,
CannotParseCyclicTerm, CannotParseCyclicTerm,
// ExpandedTermsListNotAList,
ExpectedRel, ExpectedRel,
// ExpectedTopLevelTerm,
InadmissibleFact, InadmissibleFact,
InadmissibleQueryTerm, InadmissibleQueryTerm,
InconsistentEntry, InconsistentEntry,
// InvalidDoubleQuotesDecl,
// InvalidHook,
InvalidMetaPredicateDecl, InvalidMetaPredicateDecl,
InvalidModuleDecl, InvalidModuleDecl,
InvalidModuleExport, InvalidModuleExport,
@@ -631,18 +626,12 @@ impl CompilationError {
&CompilationError::Arithmetic(..) => { &CompilationError::Arithmetic(..) => {
functor!(atom!("arithmetic_error")) functor!(atom!("arithmetic_error"))
} }
// &CompilationError::BadPendingByte =>
// functor!(atom_from_ss!("bad_pending_byte"), atom_tbl),
&CompilationError::CannotParseCyclicTerm => { &CompilationError::CannotParseCyclicTerm => {
functor!(atom!("cannot_parse_cyclic_term")) functor!(atom!("cannot_parse_cyclic_term"))
} }
// &CompilationError::ExpandedTermsListNotAList =>
// functor!(atom_tbl.build_with_static_str("expanded_terms_list_is_not_a_list")),
&CompilationError::ExpectedRel => { &CompilationError::ExpectedRel => {
functor!(atom!("expected_relation")) functor!(atom!("expected_relation"))
} }
// &CompilationError::ExpectedTopLevelTerm =>
// functor!(atom_from_ss!("expected_atom_or_cons_or_clause"), atom_tbl),
&CompilationError::InadmissibleFact => { &CompilationError::InadmissibleFact => {
functor!(atom!("inadmissible_fact")) functor!(atom!("inadmissible_fact"))
} }
@@ -652,10 +641,6 @@ impl CompilationError {
&CompilationError::InconsistentEntry => { &CompilationError::InconsistentEntry => {
functor!(atom!("inconsistent_entry")) functor!(atom!("inconsistent_entry"))
} }
// &CompilationError::InvalidDoubleQuotesDecl =>
// functor!(atom_from_ss!("invalid_double_quotes_declaration"), atom_tbl),
// &CompilationError::InvalidHook =>
// functor!(atom_from_ss!("invalid_hook"), atom_tbl),
&CompilationError::InvalidMetaPredicateDecl => { &CompilationError::InvalidMetaPredicateDecl => {
functor!(atom!("invalid_meta_predicate_decl")) functor!(atom!("invalid_meta_predicate_decl"))
} }

View File

@@ -112,30 +112,6 @@ fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, Compilatio
} }
} }
/*
fn setup_scoped_predicate_indicator(term: &mut Term) -> Result<ScopedPredicateKey, CompilationError>
{
match term {
Term::Clause(_, ref name, ref mut terms, Some(_))
if name.as_str() == ":" && terms.len() == 2 =>
{
let mut predicate_indicator = *terms.pop().unwrap();
let module_name = *terms.pop().unwrap();
let module_name = module_name
.to_constant()
.and_then(|c| c.to_atom())
.ok_or(CompilationError::InvalidModuleExport)?;
let key = setup_predicate_indicator(&mut predicate_indicator)?;
Ok((module_name, key))
}
_ => Err(CompilationError::InvalidModuleExport),
}
}
*/
fn setup_module_export( fn setup_module_export(
mut term: Term, mut term: Term,
atom_tbl: &mut AtomTable, atom_tbl: &mut AtomTable,
@@ -279,6 +255,7 @@ fn setup_qualified_import(
* - * -
* ? * ?
*/ */
fn setup_meta_predicate<'a, LS: LoadState<'a>>( fn setup_meta_predicate<'a, LS: LoadState<'a>>(
mut terms: Vec<Term>, mut terms: Vec<Term>,
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,

View File

@@ -371,28 +371,29 @@ pub enum ArithmeticError {
#[derive(Debug)] #[derive(Debug)]
pub enum ParserError { pub enum ParserError {
BackQuotedString(usize, usize), BackQuotedString(usize, usize),
UnexpectedChar(char, usize, usize), ExceededMaxArity,
UnexpectedEOF,
IO(IOError), IO(IOError),
IncompleteReduction(usize, usize), IncompleteReduction(usize, usize),
InvalidSingleQuotedCharacter(char), InvalidSingleQuotedCharacter(char),
LexicalError(lexical::Error),
MissingQuote(usize, usize), MissingQuote(usize, usize),
NonPrologChar(usize, usize), NonPrologChar(usize, usize),
ParseBigInt(usize, usize), ParseBigInt(usize, usize),
LexicalError(lexical::Error), UnexpectedChar(char, usize, usize),
UnexpectedEOF,
Utf8Error(usize, usize), Utf8Error(usize, usize),
} }
impl ParserError { impl ParserError {
pub fn line_and_col_num(&self) -> Option<(usize, usize)> { pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
match self { match self {
&ParserError::BackQuotedString(line_num, col_num) &ParserError::BackQuotedString(line_num, col_num) |
| &ParserError::UnexpectedChar(_, line_num, col_num) &ParserError::IncompleteReduction(line_num, col_num) |
| &ParserError::IncompleteReduction(line_num, col_num) &ParserError::MissingQuote(line_num, col_num) |
| &ParserError::MissingQuote(line_num, col_num) &ParserError::NonPrologChar(line_num, col_num) |
| &ParserError::NonPrologChar(line_num, col_num) &ParserError::ParseBigInt(line_num, col_num) |
| &ParserError::ParseBigInt(line_num, col_num) &ParserError::UnexpectedChar(_, line_num, col_num) |
| &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)), &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
_ => None, _ => None,
} }
} }
@@ -400,8 +401,7 @@ impl ParserError {
pub fn as_atom(&self) -> Atom { pub fn as_atom(&self) -> Atom {
match self { match self {
ParserError::BackQuotedString(..) => atom!("back_quoted_string"), ParserError::BackQuotedString(..) => atom!("back_quoted_string"),
ParserError::UnexpectedChar(..) => atom!("unexpected_char"), ParserError::ExceededMaxArity => atom!("exceeded_max_arity"),
ParserError::UnexpectedEOF => atom!("unexpected_end_of_file"),
ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"), ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"),
ParserError::InvalidSingleQuotedCharacter(..) => atom!("invalid_single_quoted_character"), ParserError::InvalidSingleQuotedCharacter(..) => atom!("invalid_single_quoted_character"),
ParserError::IO(_) => atom!("input_output_error"), ParserError::IO(_) => atom!("input_output_error"),
@@ -409,6 +409,8 @@ impl ParserError {
ParserError::MissingQuote(..) => atom!("missing_quote"), ParserError::MissingQuote(..) => atom!("missing_quote"),
ParserError::NonPrologChar(..) => atom!("non_prolog_character"), ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"), ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
ParserError::UnexpectedEOF => atom!("unexpected_end_of_file"),
ParserError::Utf8Error(..) => atom!("utf8_conversion_error"), ParserError::Utf8Error(..) => atom!("utf8_conversion_error"),
} }
} }

View File

@@ -52,7 +52,7 @@ impl MachineState {
}; };
inner.add_lines_read(num_lines_read); inner.add_lines_read(num_lines_read);
Ok(write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl)) write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl)
} }
} }
@@ -245,7 +245,7 @@ pub(crate) fn write_term_to_heap(
term: &Term, term: &Term,
heap: &mut Heap, heap: &mut Heap,
atom_tbl: &mut AtomTable, atom_tbl: &mut AtomTable,
) -> TermWriteResult { ) -> Result<TermWriteResult, ParserError> {
let term_writer = TermWriter::new(heap, atom_tbl); let term_writer = TermWriter::new(heap, atom_tbl);
term_writer.write_term_to_heap(term) term_writer.write_term_to_heap(term)
} }
@@ -311,7 +311,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
} }
} }
fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult { fn write_term_to_heap(mut self, term: &'a Term) -> Result<TermWriteResult, ParserError> {
let heap_loc = self.heap.len(); let heap_loc = self.heap.len();
for term in breadth_first_iter(term, true) { for term in breadth_first_iter(term, true) {
@@ -334,6 +334,10 @@ impl<'a, 'b> TermWriter<'a, 'b> {
self.push_stub_addr(); self.push_stub_addr();
} }
&TermRef::Clause(Level::Root, _, ref ct, subterms) => { &TermRef::Clause(Level::Root, _, ref ct, subterms) => {
if subterms.len() > MAX_ARITY {
return Err(ParserError::ExceededMaxArity);
}
self.heap.push(if subterms.len() == 0 { self.heap.push(if subterms.len() == 0 {
heap_loc_as_cell!(heap_loc + 1) heap_loc_as_cell!(heap_loc + 1)
} else { } else {
@@ -413,9 +417,9 @@ impl<'a, 'b> TermWriter<'a, 'b> {
self.modify_head_of_queue(&term, h); self.modify_head_of_queue(&term, h);
} }
TermWriteResult { Ok(TermWriteResult {
heap_loc, heap_loc,
var_dict: self.var_dict, var_dict: self.var_dict,
} })
} }
} }