mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
fix: Handle i64::MIN / -1 special case
Rust panics on i64::MIN % -1i64, so Number::divide needs to handle it specially.
This commit is contained in:
@@ -591,7 +591,11 @@ impl Number {
|
||||
}
|
||||
}
|
||||
(Number::Int(a), Number::Int(b)) => {
|
||||
if *a % *b == 0 {
|
||||
if *a == i64::MIN && *b == -1 {
|
||||
// Rust panics on i64::MIN % -1i64, so handle it specially
|
||||
let quotient = BigInt::from(*a) / BigInt::from(*b);
|
||||
Ok(Number::from_bigint_owned(quotient))
|
||||
} else if *a % *b == 0 {
|
||||
if let Some(q) = a.checked_div(*b) {
|
||||
Ok(Number::Int(q))
|
||||
} else {
|
||||
@@ -991,3 +995,41 @@ fn scientific_parts_to_bigint(mantissa: &str, exponent: i32) -> Option<BigInt> {
|
||||
|
||||
Some(value)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#![allow(clippy::expect_used)] // tests expect() to assert arithmetic results
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Regression test: `i64::MIN / -1` overflows `i64` and panics in Rust's
|
||||
/// native integer division/remainder. `divide` must promote the result
|
||||
/// instead of panicking.
|
||||
#[test]
|
||||
fn i64_min_by_negative_one() {
|
||||
let quotient = Number::Int(i64::MIN)
|
||||
.divide(&Number::Int(-1))
|
||||
.expect("division should succeed");
|
||||
|
||||
// 2^63 does not fit in i64, but does fit in u64.
|
||||
assert_eq!(quotient.as_u64(), Some(9_223_372_036_854_775_808));
|
||||
assert_eq!(quotient.as_i64(), None);
|
||||
assert_eq!(quotient.as_i128(), Some(9_223_372_036_854_775_808));
|
||||
assert_eq!(
|
||||
*quotient.to_big().expect("to_big should succeed"),
|
||||
-BigInt::from(i64::MIN)
|
||||
);
|
||||
|
||||
// The same overflow case reached via the mixed `Int`/`BigInt` path.
|
||||
let big_quotient = Number::Int(i64::MIN)
|
||||
.divide(&Number::BigInt(Rc::new(BigInt::from(-1))))
|
||||
.expect("division should succeed");
|
||||
assert_eq!(big_quotient.as_u64(), Some(9_223_372_036_854_775_808));
|
||||
|
||||
// `i64::MIN % -1` also panics natively; the result must be zero.
|
||||
let remainder = Number::Int(i64::MIN)
|
||||
.modulo(&Number::Int(-1))
|
||||
.expect("modulo should succeed");
|
||||
assert_eq!(remainder.as_i64(), Some(0));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user