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)) => {
|
(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) {
|
if let Some(q) = a.checked_div(*b) {
|
||||||
Ok(Number::Int(q))
|
Ok(Number::Int(q))
|
||||||
} else {
|
} else {
|
||||||
@@ -991,3 +995,41 @@ fn scientific_parts_to_bigint(mantissa: &str, exponent: i32) -> Option<BigInt> {
|
|||||||
|
|
||||||
Some(value)
|
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