From f7fa7ad977fa73fd104275a60dbe499abf7ded4d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 11 Jul 2016 11:34:51 -0700 Subject: [PATCH] Error on large numbers instead of parsing infinity --- json/src/de.rs | 64 ++++++++++++++++++++++++----------- json/src/error.rs | 4 +++ json_tests/tests/test_json.rs | 51 ++++++++++++++++++++++++++-- 3 files changed, 97 insertions(+), 22 deletions(-) diff --git a/json/src/de.rs b/json/src/de.rs index a6dec2420..abe24b19f 100644 --- a/json/src/de.rs +++ b/json/src/de.rs @@ -404,12 +404,7 @@ impl DeserializerImpl { let digit = (c - b'0') as i32; if overflow!(exp * 10 + digit, i32::MAX) { - // Really big exponent, just ignore the rest. - while let b'0' ... b'9' = try!(self.peek_or_null()) { - self.eat_char(); - } - exp = i32::MAX; - break; + return self.parse_exponent_overflow(pos, significand, pos_exp, visitor); } exp = exp * 10 + digit; @@ -424,29 +419,58 @@ impl DeserializerImpl { self.visit_f64_from_parts(pos, significand, final_exp, visitor) } + #[inline(never)] + fn parse_exponent_overflow(&mut self, + pos: bool, + significand: u64, + pos_exp: bool, + mut visitor: V) -> Result + where V: de::Visitor, + { + // Error instead of +/- infinity. + if significand != 0 && pos_exp { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + + while let b'0' ... b'9' = try!(self.peek_or_null()) { + self.eat_char(); + } + visitor.visit_f64(if pos { 0.0 } else { -0.0 }) + } + fn visit_f64_from_parts(&mut self, pos: bool, significand: u64, - exponent: i32, + mut exponent: i32, mut visitor: V) -> Result where V: de::Visitor, { - let f = match POW10.get(exponent.abs() as usize) { - Some(pow) => { - if exponent >= 0 { - significand as f64 * pow - } else { - significand as f64 / pow + let mut f = significand as f64; + loop { + match POW10.get(exponent.abs() as usize) { + Some(&pow) => { + if exponent >= 0 { + f *= pow; + if f.is_infinite() { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + } else { + f /= pow; + } + break; } - } - None => { - if exponent >= 0 && significand != 0 { - f64::INFINITY - } else { - 0.0 + None => { + if f == 0.0 { + break; + } + if exponent >= 0 { + return Err(self.error(ErrorCode::NumberOutOfRange)); + } + f /= 1e308; + exponent += 308; } } - }; + } visitor.visit_f64(if pos { f } else { -f }) } diff --git a/json/src/error.rs b/json/src/error.rs index e984e6351..8c0d5b60c 100644 --- a/json/src/error.rs +++ b/json/src/error.rs @@ -68,6 +68,9 @@ pub enum ErrorCode { /// Invalid number. InvalidNumber, + /// Number is bigger than the maximum value of its type. + NumberOutOfRange, + /// Invalid unicode code point. InvalidUnicodeCodePoint, @@ -105,6 +108,7 @@ impl fmt::Display for ErrorCode { ErrorCode::ExpectedSomeValue => "expected value".fmt(f), ErrorCode::InvalidEscape => "invalid escape".fmt(f), ErrorCode::InvalidNumber => "invalid number".fmt(f), + ErrorCode::NumberOutOfRange => "number out of range".fmt(f), ErrorCode::InvalidUnicodeCodePoint => "invalid unicode code point".fmt(f), ErrorCode::KeyMustBeAString => "key must be a string".fmt(f), ErrorCode::LoneLeadingSurrogateInHexEscape => "lone leading surrogate in hex escape".fmt(f), diff --git a/json_tests/tests/test_json.rs b/json_tests/tests/test_json.rs index 6a9442e75..3bc52eac5 100644 --- a/json_tests/tests/test_json.rs +++ b/json_tests/tests/test_json.rs @@ -771,6 +771,29 @@ fn test_parse_number_errors() { ("1e", Error::Syntax(ErrorCode::InvalidNumber, 1, 2)), ("1e+", Error::Syntax(ErrorCode::InvalidNumber, 1, 3)), ("1a", Error::Syntax(ErrorCode::TrailingCharacters, 1, 2)), + ("100e777777777777777777777777777", Error::Syntax(ErrorCode::NumberOutOfRange, 1, 14)), + ("-100e777777777777777777777777777", Error::Syntax(ErrorCode::NumberOutOfRange, 1, 15)), + ("1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000", // 1e309 + Error::Syntax(ErrorCode::NumberOutOfRange, 1, 310)), + ("1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + .0e9", // 1e309 + Error::Syntax(ErrorCode::NumberOutOfRange, 1, 305)), + ("1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + e9", // 1e309 + Error::Syntax(ErrorCode::NumberOutOfRange, 1, 303)), ]); } @@ -802,6 +825,7 @@ fn test_parse_negative_zero() { "-0e2", "-0.0e2", "-1e-400", + "-1e-4000000000000000000000000000000000000000000000000", ] { assert_eq!(0, from_str::(negative_zero).unwrap()); assert!(from_str::(negative_zero).unwrap().is_sign_negative(), @@ -833,11 +857,34 @@ fn test_parse_f64() { (&format!("{:?}", (u64::MAX as f64) + 1.0), (u64::MAX as f64) + 1.0), (&format!("{:?}", f64::EPSILON), f64::EPSILON), ("0.0000000000000000000000000000000000000000000000000123e50", 1.23), - ("100e777777777777777777777777777", f64::INFINITY), - ("-100e777777777777777777777777777", f64::NEG_INFINITY), ("100e-777777777777777777777777777", 0.0), ("1010101010101010101010101010101010101010", 10101010101010101010e20), ("0.1010101010101010101010101010101010101010", 0.1010101010101010101), + ("0e1000000000000000000000000000000000000000000000", 0.0), + ("1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 00000000", 1e308), + ("1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + .0e8", 1e308), + ("1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + e8", 1e308), + ("1000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000e-10", 1e308), ]); }