]> granicus.if.org Git - json-c/commitdiff
Tightening the number parsing algorithm
authorchl <dev+github@bugness.org>
Thu, 5 Feb 2015 00:34:10 +0000 (01:34 +0100)
committerchl <dev+github@bugness.org>
Thu, 5 Feb 2015 00:50:37 +0000 (01:50 +0100)
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.

json_tokener.c
tests/test_parse.c
tests/test_parse.expected

index 60e81f279d3e666c1b6b9a804442af90eed27a35..7cd879415cdc43428501b96bec99ebdf315fc2d1 100644 (file)
@@ -668,10 +668,45 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
        /* Advance until we change state */
        const char *case_start = str;
        int case_len=0;
+       int is_exponent=0;
+       int negativesign_next_possible_location=1;
        while(c && strchr(json_number_chars, c)) {
          ++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;
+         }
+         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)) {
            printbuf_memappend_fast(tok->pb, case_start, case_len);
            goto out;
index 8808d0fa61baf432e87b414190633b00961d330e..bc5389b44362446f8ebf073cf25f25fe02f3710a 100644 (file)
@@ -91,6 +91,23 @@ static void test_basic_parse()
        printf("new_obj.to_string()=%s\n", json_object_to_json_string(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\"]");
        printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
        json_object_put(new_obj);
@@ -195,6 +212,9 @@ struct incremental_step {
        { "1",                 1, 1, json_tokener_continue, 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 */
        { "\"blue\"",         -1, -1, json_tokener_success, 0 },
 
index d49cbbb18e018126c5a40b58c650eadfaeb1e970..660626012f4bf98dd87030988bb9fc58d62e2109 100644 (file)
@@ -14,6 +14,10 @@ new_obj.to_string()=-Infinity
 new_obj.to_string()=true
 new_obj.to_string()=12
 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()=[ "\nabc\n" ]
 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, 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, 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, "\""        ,   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,]    ,   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
 ==================================