Skip to content

Commit

Permalink
Added stack bound for const calculations.
Browse files Browse the repository at this point in the history
commit-id:f8cbd2f9
  • Loading branch information
orizi committed Jan 5, 2025
1 parent 055d3ef commit ac80faa
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 11 deletions.
4 changes: 4 additions & 0 deletions crates/cairo-lang-semantic/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,9 @@ impl DiagnosticEntry for SemanticDiagnostic {
SemanticDiagnosticKind::FailedConstantCalculation => {
"Failed to calculate constant.".into()
}
SemanticDiagnosticKind::ConstantCalculationDepthExceeded => {
"Constant calculation depth exceeded.".into()
}
SemanticDiagnosticKind::InnerFailedConstantCalculation(inner, _) => inner.format(db),
SemanticDiagnosticKind::DivisionByZero => "Division by zero.".into(),
SemanticDiagnosticKind::ExternTypeWithImplGenericsNotSupported => {
Expand Down Expand Up @@ -1322,6 +1325,7 @@ pub enum SemanticDiagnosticKind {
UnsupportedOutsideOfFunction(UnsupportedOutsideOfFunctionFeatureName),
UnsupportedConstant,
FailedConstantCalculation,
ConstantCalculationDepthExceeded,
InnerFailedConstantCalculation(Box<SemanticDiagnostic>, Vec<DiagnosticNote>),
DivisionByZero,
ExternTypeWithImplGenericsNotSupported,
Expand Down
20 changes: 16 additions & 4 deletions crates/cairo-lang-semantic/src/expr/test_data/constant
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,23 @@ const FAILING_CALC: felt252 = if true {

const FUNC_CALC_SUCCESS: () = panic_if_true(false);
const FUNC_CALC_FAILURE: () = panic_if_true(true);
const FUNC_CALC_SUCCESS_OPTION: felt252 = Option::Some(5).unwrap();
const FUNC_CALC_SUCCESS_RESULT1: felt252 = Result::<_, felt252>::Ok(5).unwrap();
const FUNC_CALC_SUCCESS_RESULT2: felt252 = Result::<felt252, _>::Err(5).unwrap_err();

const fn panic_if_true(cond: bool) {
if cond {
core::panic_with_felt252('assertion failed')
}
}

const FUNC_CALC_SUCCESS_OPTION: felt252 = Option::Some(5).unwrap();
const FUNC_CALC_SUCCESS_RESULT1: felt252 = Result::<_, felt252>::Ok(5).unwrap();
const FUNC_CALC_SUCCESS_RESULT2: felt252 = Result::<felt252, _>::Err(5).unwrap_err();

const FUNC_CALC_STACK_EXCEEDED: felt252 = call_myself();

const fn call_myself() -> felt252 {
call_myself()
}

//! > expected_diagnostics
error: Type not found.
--> lib.cairo:1:17
Expand Down Expand Up @@ -110,10 +117,15 @@ error: Failed to calculate constant.
const FUNC_CALC_FAILURE: () = panic_if_true(true);
^^^^^^^^^^^^^^^^^^^
note: In `test::panic_if_true`:
--> lib.cairo:30:9
--> lib.cairo:27:9
core::panic_with_felt252('assertion failed')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: Constant calculation depth exceeded.
--> lib.cairo:35:43
const FUNC_CALC_STACK_EXCEEDED: felt252 = call_myself();
^^^^^^^^^^^^^

//! > ==========================================================================

//! > Const of wrong type.
Expand Down
30 changes: 23 additions & 7 deletions crates/cairo-lang-semantic/src/items/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ pub fn validate_const_expr(ctx: &mut ComputationContext<'_>, expr_id: ExprId) {
arenas: &ctx.arenas,
vars: Default::default(),
generic_substitution: Default::default(),
depth: 0,
diagnostics: ctx.diagnostics,
};
eval_ctx.validate(expr_id);
Expand Down Expand Up @@ -419,6 +420,7 @@ pub fn resolve_const_expr_and_evaluate(
arenas: &ctx.arenas,
vars: Default::default(),
generic_substitution: Default::default(),
depth: 0,
diagnostics: ctx.diagnostics,
};
eval_ctx.validate(value.id);
Expand Down Expand Up @@ -469,6 +471,7 @@ struct ConstantEvaluateContext<'a> {
arenas: &'a Arenas,
vars: OrderedHashMap<VarId, ConstValue>,
generic_substitution: GenericSubstitution,
depth: usize,
diagnostics: &'a mut SemanticDiagnostics,
}
impl ConstantEvaluateContext<'_> {
Expand Down Expand Up @@ -903,6 +906,13 @@ impl ConstantEvaluateContext<'_> {
require(signature.is_const)?;
let generic_substitution = body_id.substitution(db).ok()?;
let body = db.function_body(concrete_body_id).ok()?;
const MAX_CONST_EVAL_DEPTH: usize = 100;
if self.depth > MAX_CONST_EVAL_DEPTH {
return Some(ConstValue::Missing(
self.diagnostics
.report(stable_ptr, SemanticDiagnosticKind::ConstantCalculationDepthExceeded),
));
}
let mut diagnostics = SemanticDiagnostics::default();
let mut inner = ConstantEvaluateContext {
db,
Expand All @@ -915,19 +925,25 @@ impl ConstantEvaluateContext<'_> {
.zip(args.iter().cloned())
.collect(),
generic_substitution,
depth: self.depth + 1,
diagnostics: &mut diagnostics,
};
let value = inner.evaluate(body.body_expr);
for diagnostic in diagnostics.build().get_all() {
let location = diagnostic.location(db.elongate());
let (inner_diag, mut notes) =
if let SemanticDiagnosticKind::InnerFailedConstantCalculation(inner_diag, notes) =
diagnostic.kind
{
let (inner_diag, mut notes) = match diagnostic.kind {
SemanticDiagnosticKind::ConstantCalculationDepthExceeded => {
self.diagnostics.report(
stable_ptr,
SemanticDiagnosticKind::ConstantCalculationDepthExceeded,
);
continue;
}
SemanticDiagnosticKind::InnerFailedConstantCalculation(inner_diag, notes) => {
(inner_diag, notes)
} else {
(diagnostic.into(), vec![])
};
}
_ => (diagnostic.into(), vec![]),
};
notes.push(DiagnosticNote::with_location(
format!("In `{}`", concrete_function.full_name(db)),
location,
Expand Down

0 comments on commit ac80faa

Please sign in to comment.