From b95c5b64aff3209da683b5d1aedccbc1ad34b8fb Mon Sep 17 00:00:00 2001 From: Stig Brautaset Date: Tue, 20 Mar 2012 22:02:50 +0000 Subject: [PATCH] Return error if precision or exponent of numbers are larger than we support. Fixes #127. (See also related issue #128) --- Classes/SBJsonTokeniser.m | 51 +++++++++++++------ NEWS.md | 1 + .../invalid/number/overflow-exponent-1/error | 1 + .../invalid/number/overflow-exponent-1/input | 1 + .../invalid/number/overflow-exponent-2/error | 1 + .../invalid/number/overflow-exponent-2/input | 1 + .../invalid/number/overflow-mantissa/error | 1 + .../invalid/number/overflow-mantissa/input | 1 + Tests/ErrorTest.m | 2 +- 9 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 Tests/Data/invalid/number/overflow-exponent-1/error create mode 100644 Tests/Data/invalid/number/overflow-exponent-1/input create mode 100644 Tests/Data/invalid/number/overflow-exponent-2/error create mode 100644 Tests/Data/invalid/number/overflow-exponent-2/input create mode 100644 Tests/Data/invalid/number/overflow-mantissa/error create mode 100644 Tests/Data/invalid/number/overflow-mantissa/input diff --git a/Classes/SBJsonTokeniser.m b/Classes/SBJsonTokeniser.m index 75d3268c..4d0f364d 100644 --- a/Classes/SBJsonTokeniser.m +++ b/Classes/SBJsonTokeniser.m @@ -36,11 +36,22 @@ #define SBStringIsSurrogateLowCharacter(character) ((character >= 0xDC00UL) && (character <= 0xDFFFUL)) #define SBStringIsSurrogateHighCharacter(character) ((character >= 0xD800UL) && (character <= 0xDBFFUL)) +static int const DECIMAL_MAX_PRECISION = 38; +static int const DECIMAL_EXPONENT_MAX = 127; +static short const DECIMAL_EXPONENT_MIN = -128; +static int const LONG_LONG_DIGITS = 20; + +static NSCharacterSet *kDecimalDigitCharacterSet; + @implementation SBJsonTokeniser @synthesize error = _error; @synthesize stream = _stream; ++ (void)initialize { + kDecimalDigitCharacterSet = [NSCharacterSet decimalDigitCharacterSet]; +} + - (id)init { self = [super init]; if (self) { @@ -241,7 +252,6 @@ - (sbjson_token_t)getStringToken:(NSObject**)token { - (sbjson_token_t)getNumberToken:(NSObject**)token { NSUInteger numberStart = _stream.index; - NSCharacterSet *digits = [NSCharacterSet decimalDigitCharacterSet]; unichar ch; if (![_stream getUnichar:&ch]) @@ -262,13 +272,13 @@ - (sbjson_token_t)getNumberToken:(NSObject**)token { if (![_stream getNextUnichar:&ch]) return sbjson_token_eof; - if ([digits characterIsMember:ch]) { + if ([kDecimalDigitCharacterSet characterIsMember:ch]) { self.error = @"Leading zero is illegal in number"; return sbjson_token_error; } } - while ([digits characterIsMember:ch]) { + while ([kDecimalDigitCharacterSet characterIsMember:ch]) { mantissa *= 10; mantissa += (ch - '0'); mantissa_length++; @@ -285,7 +295,7 @@ - (sbjson_token_t)getNumberToken:(NSObject**)token { if (![_stream getNextUnichar:&ch]) return sbjson_token_eof; - while ([digits characterIsMember:ch]) { + while ([kDecimalDigitCharacterSet characterIsMember:ch]) { mantissa *= 10; mantissa += (ch - '0'); mantissa_length++; @@ -321,7 +331,7 @@ - (sbjson_token_t)getNumberToken:(NSObject**)token { short explicit_exponent = 0; short explicit_exponent_length = 0; - while ([digits characterIsMember:ch]) { + while ([kDecimalDigitCharacterSet characterIsMember:ch]) { explicit_exponent *= 10; explicit_exponent += (ch - '0'); explicit_exponent_length++; @@ -345,20 +355,29 @@ - (sbjson_token_t)getNumberToken:(NSObject**)token { self.error = @"No digits after initial minus"; return sbjson_token_error; - } else if (mantissa_length >= 19) { - + } else if (mantissa_length > DECIMAL_MAX_PRECISION) { + self.error = @"Precision is too high"; + return sbjson_token_error; + + } else if (exponent > DECIMAL_EXPONENT_MAX || exponent < DECIMAL_EXPONENT_MIN) { + self.error = @"Exponent out of range"; + return sbjson_token_error; + } + + if (mantissa_length <= LONG_LONG_DIGITS) { + if (!isFloat && !hasExponent) { + *token = [NSNumber numberWithLongLong: isNegative ? -mantissa : mantissa]; + + } else { + *token = [NSDecimalNumber decimalNumberWithMantissa:mantissa + exponent:exponent + isNegative:isNegative]; + } + + } else { NSString *number = [_stream stringWithRange:NSMakeRange(numberStart, _stream.index - numberStart)]; *token = [NSDecimalNumber decimalNumberWithString:number]; - } else if (!isFloat && !hasExponent) { - if (!isNegative) - *token = [NSNumber numberWithUnsignedLongLong:mantissa]; - else - *token = [NSNumber numberWithLongLong:-mantissa]; - } else { - *token = [NSDecimalNumber decimalNumberWithMantissa:mantissa - exponent:exponent - isNegative:isNegative]; } return sbjson_token_number; diff --git a/NEWS.md b/NEWS.md index f15df228..a3b8a198 100644 --- a/NEWS.md +++ b/NEWS.md @@ -17,6 +17,7 @@ Miscellaneous * Added an optional comparator that is used when sorting keys. * Be more memory-efficient when parsing long strings containing escaped characters. * Add a Workspace that includes the sample projects, for ease of browsing. +* Report error for numbers with exponents outside range of -128 to 127. 3.0 (June 18th, 2011) diff --git a/Tests/Data/invalid/number/overflow-exponent-1/error b/Tests/Data/invalid/number/overflow-exponent-1/error new file mode 100644 index 00000000..4406ef98 --- /dev/null +++ b/Tests/Data/invalid/number/overflow-exponent-1/error @@ -0,0 +1 @@ +Exponent out of range diff --git a/Tests/Data/invalid/number/overflow-exponent-1/input b/Tests/Data/invalid/number/overflow-exponent-1/input new file mode 100644 index 00000000..71d2fc27 --- /dev/null +++ b/Tests/Data/invalid/number/overflow-exponent-1/input @@ -0,0 +1 @@ +[1e128] diff --git a/Tests/Data/invalid/number/overflow-exponent-2/error b/Tests/Data/invalid/number/overflow-exponent-2/error new file mode 100644 index 00000000..4406ef98 --- /dev/null +++ b/Tests/Data/invalid/number/overflow-exponent-2/error @@ -0,0 +1 @@ +Exponent out of range diff --git a/Tests/Data/invalid/number/overflow-exponent-2/input b/Tests/Data/invalid/number/overflow-exponent-2/input new file mode 100644 index 00000000..b386b91f --- /dev/null +++ b/Tests/Data/invalid/number/overflow-exponent-2/input @@ -0,0 +1 @@ +[1e-129] diff --git a/Tests/Data/invalid/number/overflow-mantissa/error b/Tests/Data/invalid/number/overflow-mantissa/error new file mode 100644 index 00000000..226a8a5b --- /dev/null +++ b/Tests/Data/invalid/number/overflow-mantissa/error @@ -0,0 +1 @@ +Precision is too high diff --git a/Tests/Data/invalid/number/overflow-mantissa/input b/Tests/Data/invalid/number/overflow-mantissa/input new file mode 100644 index 00000000..8e6e809a --- /dev/null +++ b/Tests/Data/invalid/number/overflow-mantissa/input @@ -0,0 +1 @@ +[123456789012345678901234567890123456789] diff --git a/Tests/ErrorTest.m b/Tests/ErrorTest.m index ff08c09f..210d6e98 100644 --- a/Tests/ErrorTest.m +++ b/Tests/ErrorTest.m @@ -67,7 +67,7 @@ - (void)testData { }]; - STAssertEquals(count, (NSUInteger)28, nil); + STAssertEquals(count, (NSUInteger)31, nil); } - (void)testWriteRecursion {