Bug Report
Cairo version:
commit 6a3c423a9
Current behavior:
Calling DivRem::div_rem(iN::MIN, -1) in a const context causes an unhandled compiler crash (ICE). The const-eval branch for DivRem::div_rem at crates/cairo-lang-semantic/src/items/constant.rs:931-942 bypasses validate_literal. For signed iN::MIN.div_rem(-1), the BigInt quotient is 2^(N-1) (= iN::MAX + 1), which is unrepresentable in iN. The semantic layer silently stores it as Const<iN, MAX+1> via ConstValueId::from_int. Sierra type-specialization at crates/cairo-lang-sierra-generator/src/db.rs:370 then panics:
thread 'main' panicked at crates/cairo-lang-sierra-generator/src/db.rs:370:9:
Got failure while specializing type `Const<i8, 128>`: Could not specialize type
The in-code comment at constant.rs:932 — "results are always in the range of the input type, so unwraps are ok" — is false for the signed-MIN/-1 case. The comment correctly handles the non-zero check but skips the orthogonal overflow check.
Verified on i8, i16, and i128; by structural argument also i32/i64.
| Input |
Result |
const X: i8 = -128_i8 / -1_i8; |
clean E2008 LiteralError::OutOfRange |
const X: (i8, i8) = DivRem::div_rem(-127_i8, -1); |
OK (in-range, sanity) |
const X: (i8, i8) = DivRem::div_rem(-128_i8, -1); |
ICE Got failure while specializing type `Const<i8, 128>` |
const X: (i16, i16) = DivRem::div_rem(-0x8000_i16, -1); |
ICE Got failure while specializing type `Const<i16, 32768>` |
const X: (i128, i128) = DivRem::div_rem(iN::MIN, -1); |
ICE Got failure while specializing type `Const<i128, 2^127>` |
Expected behavior:
The const-eval path for DivRem::div_rem should emit a clean E2008 LiteralError::OutOfRange diagnostic for the overflowed quotient — the same behavior as the direct / (or %) operator on the same operands, which routes through validate_literal at constant.rs:947. No ICE should be reachable from valid-looking user code.
Steps to reproduce:
- Save the snippet below as
repro.cairo.
- Run
cairo-compile repro.cairo.
- Observe the panic from
cairo-lang-sierra-generator/src/db.rs:370 instead of a normal compile diagnostic.
For contrast, replacing DivRem::div_rem(-128_i8, -1) with -128_i8 / -1_i8 produces a clean E2008 LiteralError::OutOfRange diagnostic — no ICE.
Related code:
const SILENT_OVERFLOW: (i8, i8) = DivRem::div_rem(-128_i8, -1);
fn main() -> (i8, i8) {
SILENT_OVERFLOW
}
The offending compiler branch (crates/cairo-lang-semantic/src/items/constant.rs:931-942):
id if id == self.div_rem_fn => {
// No need for non-zero check as this is type checked to begin with.
// Also results are always in the range of the input type, so `unwrap`s are ok.
return ConstValue::Struct(
vec![
ConstValueId::from_int(db, args[0].ty, &(&args[0].v / &args[1].v)),
ConstValueId::from_int(db, args[0].ty, &(&args[0].v % &args[1].v)),
],
expr.ty,
)
.intern(db);
}
Compare with the sibling div_fn / rem_fn arms at constant.rs:922-923, which fall through to the validate_literal call at constant.rs:947:
} else if let Err(err) = validate_literal(db, expr.ty, &value) {
to_missing(
self.diagnostics
.report(expr.stable_ptr.untyped(), SemanticDiagnosticKind::LiteralError(err)),
)
}
Other information:
- Suggested fix: in the
div_rem_fn branch, call validate_literal(db, args[0].ty, &q) on the quotient before storing. If it errs, emit LiteralError::OutOfRange and return missing — mirroring the / operator path.
Bug Report
Cairo version:
commit
6a3c423a9Current behavior:
Calling
DivRem::div_rem(iN::MIN, -1)in aconstcontext causes an unhandled compiler crash (ICE). The const-eval branch forDivRem::div_rematcrates/cairo-lang-semantic/src/items/constant.rs:931-942bypassesvalidate_literal. For signediN::MIN.div_rem(-1), the BigInt quotient is2^(N-1)(=iN::MAX + 1), which is unrepresentable iniN. The semantic layer silently stores it asConst<iN, MAX+1>viaConstValueId::from_int. Sierra type-specialization atcrates/cairo-lang-sierra-generator/src/db.rs:370then panics:The in-code comment at
constant.rs:932— "results are always in the range of the input type, sounwraps are ok" — is false for the signed-MIN/-1 case. The comment correctly handles the non-zero check but skips the orthogonal overflow check.Verified on
i8,i16, andi128; by structural argument alsoi32/i64.const X: i8 = -128_i8 / -1_i8;LiteralError::OutOfRangeconst X: (i8, i8) = DivRem::div_rem(-127_i8, -1);const X: (i8, i8) = DivRem::div_rem(-128_i8, -1);Got failure while specializing type `Const<i8, 128>`const X: (i16, i16) = DivRem::div_rem(-0x8000_i16, -1);Got failure while specializing type `Const<i16, 32768>`const X: (i128, i128) = DivRem::div_rem(iN::MIN, -1);Got failure while specializing type `Const<i128, 2^127>`Expected behavior:
The const-eval path for
DivRem::div_remshould emit a cleanE2008 LiteralError::OutOfRangediagnostic for the overflowed quotient — the same behavior as the direct/(or%) operator on the same operands, which routes throughvalidate_literalatconstant.rs:947. No ICE should be reachable from valid-looking user code.Steps to reproduce:
repro.cairo.cairo-compile repro.cairo.cairo-lang-sierra-generator/src/db.rs:370instead of a normal compile diagnostic.For contrast, replacing
DivRem::div_rem(-128_i8, -1)with-128_i8 / -1_i8produces a cleanE2008 LiteralError::OutOfRangediagnostic — no ICE.Related code:
The offending compiler branch (
crates/cairo-lang-semantic/src/items/constant.rs:931-942):Compare with the sibling
div_fn/rem_fnarms atconstant.rs:922-923, which fall through to thevalidate_literalcall atconstant.rs:947:Other information:
div_rem_fnbranch, callvalidate_literal(db, args[0].ty, &q)on the quotient before storing. If it errs, emitLiteralError::OutOfRangeand return missing — mirroring the/operator path.