Skip to content

Commit 1fc3523

Browse files
authored
Add range check to parse_timestamp_float (#6525)
1 parent 9a060dd commit 1fc3523

1 file changed

Lines changed: 24 additions & 4 deletions

File tree

quickwit/quickwit-datetime/src/date_time_parsing.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ const MIN_TIMESTAMP_SECONDS: i64 = 72_057_595;
2727
// Maximum supported timestamp value in seconds (16 Mar 2242 12:56:31 GMT).
2828
const MAX_TIMESTAMP_SECONDS: i64 = 8_589_934_591;
2929

30+
/// Builds the error returned when a Unix timestamp falls outside the range Quickwit supports.
31+
fn unsupported_timestamp_error(timestamp: impl std::fmt::Display) -> String {
32+
format!(
33+
"failed to parse unix timestamp `{timestamp}`. Quickwit only supports timestamp values \
34+
ranging from `13 Apr 1972 23:59:55` to `16 Mar 2242 12:56:31`"
35+
)
36+
}
37+
3038
pub fn parse_date_time_str(
3139
date_time_str: &str,
3240
date_time_formats: &[DateTimeInputFormat],
@@ -76,6 +84,12 @@ pub fn parse_timestamp_float(
7684
.join("`, `")
7785
));
7886
}
87+
// We apply the same range check as the integer path (`parse_timestamp`) to reject out-of-range
88+
// values instead of silently wrapping them when casting the `u128` nanoseconds to `i64`
89+
// below.
90+
if !(MIN_TIMESTAMP_SECONDS as f64..=MAX_TIMESTAMP_SECONDS as f64).contains(&timestamp) {
91+
return Err(unsupported_timestamp_error(timestamp));
92+
}
7993
let duration_since_epoch = Duration::try_from_secs_f64(timestamp)
8094
.map_err(|error| format!("failed to parse datetime `{timestamp}`: {error}"))?;
8195
let timestamp_nanos = duration_since_epoch.as_nanos() as i64;
@@ -167,10 +181,7 @@ pub fn parse_timestamp(timestamp: i64) -> Result<TantivyDateTime, String> {
167181
MIN_TIMESTAMP_NANOS..=MAX_TIMESTAMP_NANOS => {
168182
Ok(TantivyDateTime::from_timestamp_nanos(timestamp))
169183
}
170-
_ => Err(format!(
171-
"failed to parse unix timestamp `{timestamp}`. Quickwit only support timestamp values \
172-
ranging from `13 Apr 1972 23:59:55` to `16 Mar 2242 12:56:31`"
173-
)),
184+
_ => Err(unsupported_timestamp_error(timestamp)),
174185
}
175186
}
176187

@@ -386,6 +397,15 @@ mod tests {
386397
`iso8601`, `rfc2822`"
387398
);
388399
}
400+
{
401+
// Out-of-range float values used to silently wrap when casting `u128` nanoseconds to
402+
// `i64`. They must now be rejected, just like the integer path does.
403+
let error = parse_timestamp_float(9e18, &[DateTimeInputFormat::Timestamp]).unwrap_err();
404+
assert!(error.contains("failed to parse unix timestamp"), "{error}");
405+
406+
let error = parse_timestamp_float(-1.0, &[DateTimeInputFormat::Timestamp]).unwrap_err();
407+
assert!(error.contains("failed to parse unix timestamp"), "{error}");
408+
}
389409
}
390410

391411
#[test]

0 commit comments

Comments
 (0)