Some badly formated "numbers" could get partly parsed, resulting in truncated results instead of raising an error. Examples : '1.2.3' -> (double)1.2 '2015-01-15' -> (int)2015 This patch is not perfect (ex: input can still end with a 'E', which is forbidden by json.org doc) but should avoid non-sensically formated input. Tests added.tags/json-c-0.13-20171207
| @@ -668,10 +668,45 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, | |||||
| /* Advance until we change state */ | /* Advance until we change state */ | ||||
| const char *case_start = str; | const char *case_start = str; | ||||
| int case_len=0; | int case_len=0; | ||||
| int is_exponent=0; | |||||
| int negativesign_next_possible_location=1; | |||||
| while(c && strchr(json_number_chars, c)) { | while(c && strchr(json_number_chars, c)) { | ||||
| ++case_len; | ++case_len; | ||||
| if(c == '.' || c == 'e' || c == 'E') | |||||
| /* non-digit characters checks */ | |||||
| /* note: since the main loop condition to get here was | |||||
| an input starting with 0-9 or '-', we are | |||||
| protected from input starting with '.' or | |||||
| e/E. */ | |||||
| if (c == '.') { | |||||
| if (tok->is_double != 0) { | |||||
| /* '.' can only be found once, and out of the exponent part. | |||||
| Thus, if the input is already flagged as double, it | |||||
| is invalid. */ | |||||
| tok->err = json_tokener_error_parse_number; | |||||
| goto out; | |||||
| } | |||||
| tok->is_double = 1; | tok->is_double = 1; | ||||
| } | |||||
| if (c == 'e' || c == 'E') { | |||||
| if (is_exponent != 0) { | |||||
| /* only one exponent possible */ | |||||
| tok->err = json_tokener_error_parse_number; | |||||
| goto out; | |||||
| } | |||||
| is_exponent = 1; | |||||
| tok->is_double = 1; | |||||
| /* the exponent part can begin with a negative sign */ | |||||
| negativesign_next_possible_location = case_len + 1; | |||||
| } | |||||
| if (c == '-' && case_len != negativesign_next_possible_location) { | |||||
| /* If the negative sign is not where expected (ie | |||||
| start of input or start of exponent part), the | |||||
| input is invalid. */ | |||||
| tok->err = json_tokener_error_parse_number; | |||||
| goto out; | |||||
| } | |||||
| if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { | if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { | ||||
| printbuf_memappend_fast(tok->pb, case_start, case_len); | printbuf_memappend_fast(tok->pb, case_start, case_len); | ||||
| goto out; | goto out; | ||||
| @@ -91,6 +91,23 @@ static void test_basic_parse() | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | ||||
| json_object_put(new_obj); | json_object_put(new_obj); | ||||
| new_obj = json_tokener_parse("12.3.4"); /* non-sensical, returns null */ | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| /* was returning (int)2015 before patch, should return null */ | |||||
| new_obj = json_tokener_parse("2015-01-15"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("{\"FoO\" : -12.3E512}"); | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("{\"FoO\" : -12.3E51.2}"); /* non-sensical, returns null */ | |||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | |||||
| json_object_put(new_obj); | |||||
| new_obj = json_tokener_parse("[\"\\n\"]"); | new_obj = json_tokener_parse("[\"\\n\"]"); | ||||
| printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); | ||||
| json_object_put(new_obj); | json_object_put(new_obj); | ||||
| @@ -195,6 +212,9 @@ struct incremental_step { | |||||
| { "1", 1, 1, json_tokener_continue, 0 }, | { "1", 1, 1, json_tokener_continue, 0 }, | ||||
| { "2", 2, 1, json_tokener_success, 0 }, | { "2", 2, 1, json_tokener_success, 0 }, | ||||
| /* Some bad formatting. Check we get the correct error status */ | |||||
| { "2015-01-15", 10, 4, json_tokener_error_parse_number, 1 }, | |||||
| /* Strings have a well defined end point, so we can stop at the quote */ | /* Strings have a well defined end point, so we can stop at the quote */ | ||||
| { "\"blue\"", -1, -1, json_tokener_success, 0 }, | { "\"blue\"", -1, -1, json_tokener_success, 0 }, | ||||
| @@ -14,6 +14,10 @@ new_obj.to_string()=-Infinity | |||||
| new_obj.to_string()=true | new_obj.to_string()=true | ||||
| new_obj.to_string()=12 | new_obj.to_string()=12 | ||||
| new_obj.to_string()=12.3 | new_obj.to_string()=12.3 | ||||
| new_obj.to_string()=null | |||||
| new_obj.to_string()=null | |||||
| new_obj.to_string()={ "FoO": -12.3E512 } | |||||
| new_obj.to_string()=null | |||||
| new_obj.to_string()=[ "\n" ] | new_obj.to_string()=[ "\n" ] | ||||
| new_obj.to_string()=[ "\nabc\n" ] | new_obj.to_string()=[ "\nabc\n" ] | ||||
| new_obj.to_string()=[ null ] | new_obj.to_string()=[ null ] | ||||
| @@ -48,6 +52,7 @@ json_tokener_parse_ex(tok, {"x": 123 }"X", 14) ... OK: got object of type [obje | |||||
| json_tokener_parse_ex(tok, "Y" , 3) ... OK: got object of type [string]: "Y" | json_tokener_parse_ex(tok, "Y" , 3) ... OK: got object of type [string]: "Y" | ||||
| json_tokener_parse_ex(tok, 1 , 1) ... OK: got correct error: continue | json_tokener_parse_ex(tok, 1 , 1) ... OK: got correct error: continue | ||||
| json_tokener_parse_ex(tok, 2 , 2) ... OK: got object of type [int]: 12 | json_tokener_parse_ex(tok, 2 , 2) ... OK: got object of type [int]: 12 | ||||
| json_tokener_parse_ex(tok, 2015-01-15 , 10) ... OK: got correct error: number expected | |||||
| json_tokener_parse_ex(tok, "blue" , 6) ... OK: got object of type [string]: "blue" | json_tokener_parse_ex(tok, "blue" , 6) ... OK: got object of type [string]: "blue" | ||||
| json_tokener_parse_ex(tok, "\"" , 4) ... OK: got object of type [string]: "\"" | json_tokener_parse_ex(tok, "\"" , 4) ... OK: got object of type [string]: "\"" | ||||
| json_tokener_parse_ex(tok, "\\" , 4) ... OK: got object of type [string]: "\\" | json_tokener_parse_ex(tok, "\\" , 4) ... OK: got object of type [string]: "\\" | ||||
| @@ -61,5 +66,5 @@ json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got object of type [array] | |||||
| json_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character | json_tokener_parse_ex(tok, [1,2,,3,] , 9) ... OK: got correct error: unexpected character | ||||
| json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got correct error: unexpected character | json_tokener_parse_ex(tok, [1,2,3,] , 8) ... OK: got correct error: unexpected character | ||||
| json_tokener_parse_ex(tok, {"a":1,} , 8) ... OK: got correct error: unexpected character | json_tokener_parse_ex(tok, {"a":1,} , 8) ... OK: got correct error: unexpected character | ||||
| End Incremental Tests OK=29 ERROR=0 | |||||
| End Incremental Tests OK=30 ERROR=0 | |||||
| ================================== | ================================== | ||||