Skip to content

Commit

Permalink
Return error if precision or exponent of numbers are larger than we s…
Browse files Browse the repository at this point in the history
…upport. Fixes #127. (See also related issue #128)
  • Loading branch information
Stig Brautaset authored and Stig Brautaset committed Mar 21, 2012
1 parent 4bc6ae1 commit b95c5b6
Show file tree
Hide file tree
Showing 9 changed files with 43 additions and 17 deletions.
51 changes: 35 additions & 16 deletions Classes/SBJsonTokeniser.m
Expand Up @@ -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) {
Expand Down Expand Up @@ -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])
Expand All @@ -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++;
Expand All @@ -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++;
Expand Down Expand Up @@ -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++;
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions Tests/Data/invalid/number/overflow-exponent-1/error
@@ -0,0 +1 @@
Exponent out of range
1 change: 1 addition & 0 deletions Tests/Data/invalid/number/overflow-exponent-1/input
@@ -0,0 +1 @@
[1e128]
1 change: 1 addition & 0 deletions Tests/Data/invalid/number/overflow-exponent-2/error
@@ -0,0 +1 @@
Exponent out of range
1 change: 1 addition & 0 deletions Tests/Data/invalid/number/overflow-exponent-2/input
@@ -0,0 +1 @@
[1e-129]
1 change: 1 addition & 0 deletions Tests/Data/invalid/number/overflow-mantissa/error
@@ -0,0 +1 @@
Precision is too high
1 change: 1 addition & 0 deletions Tests/Data/invalid/number/overflow-mantissa/input
@@ -0,0 +1 @@
[123456789012345678901234567890123456789]
2 changes: 1 addition & 1 deletion Tests/ErrorTest.m
Expand Up @@ -67,7 +67,7 @@ - (void)testData {

}];

STAssertEquals(count, (NSUInteger)28, nil);
STAssertEquals(count, (NSUInteger)31, nil);
}

- (void)testWriteRecursion {
Expand Down

0 comments on commit b95c5b6

Please sign in to comment.