Skip to content

Commit

Permalink
fix!(parse_json): (lossy) convert large numbers to float to avoid int…
Browse files Browse the repository at this point in the history
…eger overflow (#570)
  • Loading branch information
pront committed Nov 21, 2023
1 parent 8dc2dff commit 5b2568b
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## unreleased
* `parse_regex_all` `pattern` param can now be resolved from a variable
* fixed `parse_json` data corruption issue for numbers greater or equal to `i64::MAX`

## `0.8.0` (2023-10-31)

Expand Down
16 changes: 14 additions & 2 deletions src/stdlib/parse_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,8 @@ fn type_def() -> TypeDef {

#[cfg(test)]
mod tests {
use crate::value;

use super::*;
use crate::value;

test_function![
parse_json => ParseJson;
Expand Down Expand Up @@ -310,5 +309,18 @@ mod tests {
want: Err("max_depth value should be greater than 0 and less than 128, got 129"),
tdef: type_def(),
}

// // TODO: provide a function version of the `test_function!` macro.
max_int {
args: func_args![ value: format!("{{\"num\": {}}}", i64::MAX - 1)],
want: Ok(value!({"num": 9_223_372_036_854_775_806_i64})),
tdef: type_def(),
}

lossy_float_conversion {
args: func_args![ value: r#"{"num": 9223372036854775808}"#],
want: Ok(value!({"num": 9.223_372_036_854_776e18})),
tdef: type_def(),
}
];
}
3 changes: 1 addition & 2 deletions src/value/value.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
//! Contains the main "Value" type for Vector and VRL, as well as helper methods.

use std::collections::BTreeMap;

use bytes::{Bytes, BytesMut};
use chrono::{DateTime, SecondsFormat, Utc};
use ordered_float::NotNan;
use std::collections::BTreeMap;

pub use iter::{IterItem, ValueIter};

Expand Down
20 changes: 18 additions & 2 deletions src/value/value/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,24 @@ impl<'de> Deserialize<'de> for Value {
}

#[inline]
fn visit_u64<E>(self, value: u64) -> Result<Value, E> {
Ok((value as i64).into())
fn visit_u64<E>(self, value: u64) -> Result<Value, E>
where
E: serde::de::Error,
{
if let Ok(value) = i64::try_from(value) {
Ok(value.into())
} else {
// TODO: Address this issue by providing a lossless conversion option.
#[allow(clippy::cast_precision_loss)]
let converted_value = value as f64;
let wrapped_value = NotNan::new(converted_value).map_err(|_| {
SerdeError::invalid_value(
serde::de::Unexpected::Float(converted_value),
&self,
)
})?;
Ok(Value::Float(wrapped_value))
}
}

#[inline]
Expand Down

0 comments on commit 5b2568b

Please sign in to comment.