1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

seq:add bounds for exponents

Add bounds for exponents to avoid overflow issues for inputs like 'seq
1e-9223372036854775808'
This commit is contained in:
Alexander Shirokov 2025-01-15 20:54:52 +01:00
parent dca0ec0e65
commit b3c0633b95
No known key found for this signature in database
GPG key ID: 6020E4D7AFA8ECE7
2 changed files with 36 additions and 9 deletions

View file

@ -103,15 +103,18 @@ fn parse_exponent_no_decimal(s: &str, j: usize) -> Result<PreciseNumber, ParseNu
// displayed in decimal notation. For example, "1e-2" will be // displayed in decimal notation. For example, "1e-2" will be
// displayed as "0.01", but "1e2" will be displayed as "100", // displayed as "0.01", but "1e2" will be displayed as "100",
// without a decimal point. // without a decimal point.
let x: BigDecimal = {
let parsed_decimal = s // In ['BigDecimal'], a positive scale represents a negative power of 10.
.parse::<BigDecimal>() // This means the exponent value from the number must be inverted. However,
.map_err(|_| ParseNumberError::Float)?; // since the |i64::MIN| > |i64::MAX| (i.e. |2^63| > |2^631|) inverting a
if parsed_decimal == BigDecimal::zero() { // valid negative value could result in an overflow. To prevent this, we
BigDecimal::zero() // limit the minimal value with i64::MIN + 1.
} else { let exponent = exponent.max(i64::MIN + 1);
parsed_decimal let base: BigInt = s[..j].parse().map_err(|_| ParseNumberError::Float)?;
} let x = if base.is_zero() {
BigDecimal::zero()
} else {
BigDecimal::from_bigint(base, -exponent)
}; };
let num_integral_digits = if is_minus_zero_float(s, &x) { let num_integral_digits = if is_minus_zero_float(s, &x) {
@ -599,4 +602,18 @@ mod tests {
assert_eq!(num_fractional_digits("-0e-1"), 1); assert_eq!(num_fractional_digits("-0e-1"), 1);
assert_eq!(num_fractional_digits("-0.0e-1"), 2); assert_eq!(num_fractional_digits("-0.0e-1"), 2);
} }
#[test]
fn test_parse_min_exponents() {
// Make sure exponents <= i64::MIN do not cause errors
assert!("1e-9223372036854775807".parse::<PreciseNumber>().is_ok());
assert!("1e-9223372036854775808".parse::<PreciseNumber>().is_ok());
}
#[test]
fn test_parse_max_exponents() {
// Make sure exponents >= i64::MAX cause errors
assert!("1e9223372036854775807".parse::<PreciseNumber>().is_err());
assert!("1e9223372036854775808".parse::<PreciseNumber>().is_err());
}
} }

View file

@ -878,6 +878,16 @@ fn test_parse_float_gnu_coreutils() {
.stdout_only("0.000000\n0.000001\n0.000002\n0.000003\n"); .stdout_only("0.000000\n0.000001\n0.000002\n0.000003\n");
} }
#[test]
fn test_parse_out_of_bounds_exponents() {
// The value 1e-9223372036854775808 is used in GNU Coreutils and BigDecimal tests to verify
// overflows and undefined behavior. Let's test the value too.
new_ucmd!()
.args(&["1e-9223372036854775808"])
.succeeds()
.stdout_only("");
}
#[ignore] #[ignore]
#[test] #[test]
fn test_parse_valid_hexadecimal_float_format_issues() { fn test_parse_valid_hexadecimal_float_format_issues() {