Sitelet https://github.com/starkware-libs/cairo/issues/10132
Skip to content

bug: Const DivRem signed MIN over minus one ICE #10132

Description

@researchzero-sec

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:

  1. Save the snippet below as repro.cairo.
  2. Run cairo-compile repro.cairo.
  3. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions