diff options
author | Petri Lehtinen <petri@digip.org> | 2009-09-13 13:15:34 +0300 |
---|---|---|
committer | Petri Lehtinen <petri@digip.org> | 2009-09-14 10:28:03 +0300 |
commit | 6d8c287032f9b87f1d787d41ecf9c37cdf29892c (patch) | |
tree | a3dd2803cfa176720981ae68ac8356f64334fb6e /src | |
parent | ab3764ed0a376633037599773010feeba64ec1a3 (diff) | |
download | jansson-6d8c287032f9b87f1d787d41ecf9c37cdf29892c.zip jansson-6d8c287032f9b87f1d787d41ecf9c37cdf29892c.tar.gz jansson-6d8c287032f9b87f1d787d41ecf9c37cdf29892c.tar.bz2 |
load: Check for integer and real overlfows and underflows
Backported from master, commit 5406c2b3d347505149d382213b6f318f8c35de6a:
* deleted test/testdata/invalid-stripped because the stripped tests
don't exist in 1.0
Diffstat (limited to 'src')
-rw-r--r-- | src/load.c | 49 |
1 files changed, 40 insertions, 9 deletions
@@ -8,6 +8,7 @@ #define _GNU_SOURCE #include <ctype.h> #include <errno.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -399,10 +400,11 @@ out: free(lex->value.string); } -static void lex_scan_number(lex_t *lex, char c, json_error_t *error) +static int lex_scan_number(lex_t *lex, char c, json_error_t *error) { const char *saved_text; char *end; + double value; lex->token = TOKEN_INVALID; @@ -423,14 +425,26 @@ static void lex_scan_number(lex_t *lex, char c, json_error_t *error) } if(c != '.' && c != 'E' && c != 'e') { + long value; + lex_unget_unsave(lex, c); - lex->token = TOKEN_INTEGER; saved_text = strbuffer_value(&lex->saved_text); - lex->value.integer = strtol(saved_text, &end, 10); + value = strtol(saved_text, &end, 10); assert(end == saved_text + lex->saved_text.length); - return; + if((value == LONG_MAX && errno == ERANGE) || value > INT_MAX) { + error_set(error, lex, "too big integer"); + goto out; + } + else if((value == LONG_MIN && errno == ERANGE) || value < INT_MIN) { + error_set(error, lex, "too big negative integer"); + goto out; + } + + lex->token = TOKEN_INTEGER; + lex->value.integer = (int)value; + return 0; } if(c == '.') { @@ -460,14 +474,29 @@ static void lex_scan_number(lex_t *lex, char c, json_error_t *error) } lex_unget_unsave(lex, c); - lex->token = TOKEN_REAL; saved_text = strbuffer_value(&lex->saved_text); - lex->value.real = strtod(saved_text, &end); + value = strtod(saved_text, &end); assert(end == saved_text + lex->saved_text.length); + if(value == 0 && errno == ERANGE) { + error_set(error, lex, "real number underflow"); + goto out; + } + + /* Cannot test for +/-HUGE_VAL because the HUGE_VAL constant is + only defined in C99 mode. So let's trust in sole errno. */ + else if(errno == ERANGE) { + error_set(error, lex, "real number overflow"); + goto out; + } + + lex->token = TOKEN_REAL; + lex->value.real = value; + return 0; + out: - return; + return -1; } static int lex_scan(lex_t *lex, json_error_t *error) @@ -506,8 +535,10 @@ static int lex_scan(lex_t *lex, json_error_t *error) else if(c == '"') lex_scan_string(lex, error); - else if(isdigit(c) || c == '-') - lex_scan_number(lex, c, error); + else if(isdigit(c) || c == '-') { + if(lex_scan_number(lex, c, error)) + goto out; + } else if(isupper(c) || islower(c)) { /* eat up the whole identifier for clearer error messages */ |