Skip to content

Commit 3d727ca

Browse files
authored
uucore: parse_time: avoid expensive with_scale(9) for huge inputs
The conversion routine used to parse the time into a BigDecimal and normalize it into nanoseconds; however, for an input like 1e6666666666668320 it would require allocating a number with 6666666666668329 zeroes, which is obviously suboptimal (and redundant, as `Duration` uses `u64` for seconds). Fixes #8634.
1 parent 7dbeb8f commit 3d727ca

File tree

1 file changed

+9
-1
lines changed

1 file changed

+9
-1
lines changed

src/uucore/src/lib/features/parser/parse_time.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,14 @@ pub fn from_str(string: &str, allow_suffixes: bool) -> Result<Duration, String>
8080

8181
// Allow non-negative durations (-0 is fine), and infinity.
8282
let num = match num {
83-
ExtendedBigDecimal::BigDecimal(bd) if !bd.is_negative() => bd,
83+
ExtendedBigDecimal::BigDecimal(bd) if !bd.is_negative() => {
84+
if bd.fractional_digit_count() <= -20 {
85+
// bd >= 10^20 > u64::MAX -- early return to avoid
86+
// potentially expensive to-nanoseconds conversion
87+
return Ok(Duration::MAX);
88+
}
89+
bd
90+
}
8491
ExtendedBigDecimal::MinusZero => 0.into(),
8592
ExtendedBigDecimal::Infinity => return Ok(Duration::MAX),
8693
_ => return Err(format!("invalid time interval {}", string.quote())),
@@ -128,6 +135,7 @@ mod tests {
128135
fn test_overflow() {
129136
// u64 seconds overflow (in Duration)
130137
assert_eq!(from_str("9223372036854775808d", true), Ok(Duration::MAX));
138+
assert_eq!(from_str("1e6666666666668320", true), Ok(Duration::MAX));
131139
// ExtendedBigDecimal overflow
132140
assert_eq!(from_str("1e92233720368547758080", false), Ok(Duration::MAX));
133141
assert_eq!(from_str("1e92233720368547758080", false), Ok(Duration::MAX));

0 commit comments

Comments
 (0)