Sitelet https://github.com/starkware-libs/cairo/commit/6eac8317437f0cd62f56654c27677b8dc472f2b8
Skip to content

Commit 6eac831

Browse files
oriziclaude
andcommitted
bug fix(semantic): Validate quotient in const DivRem to avoid signed MIN/-1 ICE.
The const-eval path for `DivRem::div_rem` stored the quotient without validating it against the input type's range. For signed `iN::MIN / -1` the quotient is `2^(N-1)` (= `iN::MAX + 1`), which is unrepresentable in `iN`; the out-of-range value was silently stored and later caused an ICE in sierra type-specialization (`Got failure while specializing type Const<i8, 128>`). Now the quotient is validated via `validate_literal`, emitting a clean E2008 LiteralError::OutOfRange — matching the `/` operator path. Fixes #10132. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8914649 commit 6eac831

4 files changed

Lines changed: 25 additions & 9 deletions

File tree

‎Cargo.lock‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎crates/cairo-lang-semantic/Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ id-arena.workspace = true
2626
indoc.workspace = true
2727
itertools = { workspace = true, default-features = true }
2828
num-bigint = { workspace = true, default-features = true }
29+
num-integer = { workspace = true, default-features = true }
2930
num-traits = { workspace = true, default-features = true }
3031
postcard.workspace = true
3132
salsa.workspace = true

‎crates/cairo-lang-semantic/src/expr/test_data/constant‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,9 @@ const VALID_LE: () = assert(1_usize <= 1);
211211
const VALID_GT: () = assert(2_usize > 1);
212212
const VALID_GE: () = assert(1_usize >= 1);
213213
const VALID_DIVREM: () = assert(DivRem::div_rem(5_u8, 2) == (2, 1));
214+
// The quotient of signed `MIN / -1` overflows the type, and should emit a clean diagnostic
215+
// rather than silently storing an out-of-range value (which later ICEs in sierra-gen).
216+
const DIVREM_SIGNED_MIN_OVERFLOW: (i8, i8) = DivRem::div_rem(-128_i8, -1);
214217

215218
const MATCH_VALUE: () = assert(match 1_u8 {
216219
_ => 1,
@@ -300,22 +303,27 @@ note: In `test::assert`:
300303
core::panic_with_felt252('failed assertion')
301304
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
302305

306+
error[E2008]: The value does not fit within the range of type core::integer::i8.
307+
--> lib.cairo:69:46
308+
const DIVREM_SIGNED_MIN_OVERFLOW: (i8, i8) = DivRem::div_rem(-128_i8, -1);
309+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
310+
303311
error[E2129]: Constant calculation depth exceeded.
304-
--> lib.cairo:92:43
312+
--> lib.cairo:95:43
305313
const FUNC_CALC_STACK_EXCEEDED: felt252 = call_myself();
306314
^^^^^^^^^^^^^
307315

308316
error[E2130]: Failed to calculate constant.
309-
--> lib.cairo:99:37
317+
--> lib.cairo:102:37
310318
const NON_ZERO_ZERO: NonZero<u64> = my_unwrap(ZERO.try_into());
311319
^^^^^^^^^^^^^^^^^^^^^^^^^^
312320
note: In `test::my_unwrap::<core::zeroable::NonZero::<core::integer::u64>>`:
313-
--> lib.cairo:105:17
321+
--> lib.cairo:108:17
314322
None => core::panic_with_felt252('bad value'),
315323
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
316324

317325
error[E2128]: Failed to calculate constant.
318-
--> lib.cairo:111:9
326+
--> lib.cairo:114:9
319327
core::panic_with_felt252('should fail')
320328
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
321329

‎crates/cairo-lang-semantic/src/items/constant.rs‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use cairo_lang_utils::unordered_hash_set::UnorderedHashSet;
2222
use cairo_lang_utils::{Intern, define_short_id, extract_matches, require, try_extract_matches};
2323
use itertools::Itertools;
2424
use num_bigint::BigInt;
25+
use num_integer::Integer;
2526
use num_traits::{ToPrimitive, Zero};
2627
use salsa::Database;
2728
use starknet_types_core::felt::{CAIRO_PRIME_BIGINT, Felt as Felt252};
@@ -931,12 +932,17 @@ impl<'a, 'r, 'mt> ConstantEvaluateContext<'a, 'r, 'mt> {
931932
id if id == self.ge_fn => return bool_value(args[0].v >= args[1].v),
932933
id if id == self.div_rem_fn => {
933934
// No need for non-zero check as this is type checked to begin with.
934-
// Also results are always in the range of the input type, so `unwrap`s are ok.
935+
let (q, r) = args[0].v.div_rem(&args[1].v);
936+
let ty = args[0].ty;
937+
// The quotient may overflow for signed `MIN / -1`, so it must be validated.
938+
if let Err(err) = validate_literal(db, ty, &q) {
939+
return to_missing(self.diagnostics.report(
940+
expr.stable_ptr.untyped(),
941+
SemanticDiagnosticKind::LiteralError(err),
942+
));
943+
}
935944
return ConstValue::Struct(
936-
vec![
937-
ConstValueId::from_int(db, args[0].ty, &(&args[0].v / &args[1].v)),
938-
ConstValueId::from_int(db, args[0].ty, &(&args[0].v % &args[1].v)),
939-
],
945+
vec![ConstValueId::from_int(db, ty, &q), ConstValueId::from_int(db, ty, &r)],
940946
expr.ty,
941947
)
942948
.intern(db);

0 commit comments

Comments
 (0)