]> granicus.if.org Git - json-c/commitdiff
Rewrite the json_tokener_state_inf handling in json_tokener to be simpler, and avoid...
authorEric Haszlakiewicz <erh+git@nimenees.com>
Mon, 27 Nov 2017 05:20:11 +0000 (00:20 -0500)
committerEric Haszlakiewicz <erh+git@nimenees.com>
Mon, 27 Nov 2017 05:20:11 +0000 (00:20 -0500)
json_tokener.c

index 4aaa89f195060b99c1b2755066cf1615d5be7db3..416058d405e3358d3b719c4decda996d202a9c35 100644 (file)
@@ -57,7 +57,8 @@
 static const char json_null_str[] = "null";
 static const int json_null_str_len = sizeof(json_null_str) - 1;
 static const char json_inf_str[] = "Infinity";
-static const int json_inf_str_len = sizeof(json_inf_str) - 1;
+static const char json_inf_str_lower[] = "infinity";
+static const unsigned int json_inf_str_len = sizeof(json_inf_str) - 1;
 static const char json_nan_str[] = "NaN";
 static const int json_nan_str_len = sizeof(json_nan_str) - 1;
 static const char json_true_str[] = "true";
@@ -383,40 +384,55 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
       tok->depth--;
       goto redo_char;
 
-    case json_tokener_state_inf: /* aka starts with 'i' */
+    case json_tokener_state_inf: /* aka starts with 'i' (or 'I', or "-i", or "-I") */
       {
-       size_t size_inf;
+       /* If we were guaranteed to have len set, then we could (usually) handle
+        * the entire "Infinity" check in a single strncmp (strncasecmp), but
+        * since len might be -1 (i.e. "read until \0"), we need to check it
+        * a character at a time.
+        * Trying to handle it both ways would make this code considerably more
+        * complicated with likely little performance benefit.
+        */
        int is_negative = 0;
-       char *infbuf;
+       const char *_json_inf_str = json_inf_str;
+       if (!(tok->flags & JSON_TOKENER_STRICT))
+               _json_inf_str = json_inf_str_lower;
 
-       printbuf_memappend_fast(tok->pb, &c, 1);
-       size_inf = json_min(tok->st_pos+1, json_inf_str_len);
-       infbuf = tok->pb->buf;
-       if (*infbuf == '-')
-       {
-               infbuf++;
-               is_negative = 1;
-       }
-       if ((!(tok->flags & JSON_TOKENER_STRICT) &&
-                 strncasecmp(json_inf_str, infbuf, size_inf) == 0) ||
-                (strncmp(json_inf_str, infbuf, size_inf) == 0)
-               )
+       /* Note: tok->st_pos must be 0 when state is set to json_tokener_state_inf */
+       while (tok->st_pos < (int)json_inf_str_len)
        {
-               if (tok->st_pos == json_inf_str_len)
+               char inf_char = *str;
+               if (!(tok->flags & JSON_TOKENER_STRICT))
+                       inf_char = tolower(*str);
+               if (inf_char != _json_inf_str[tok->st_pos])
                {
-                       current = json_object_new_double(is_negative
-                                                        ? -INFINITY : INFINITY);
-                       if(current == NULL)
-                           goto out;
-                       saved_state = json_tokener_state_finish;
-                       state = json_tokener_state_eatws;
-                       goto redo_char;
+                       tok->err = json_tokener_error_parse_unexpected;
+                       goto out;
+               }
+               tok->st_pos++;
+               (void)ADVANCE_CHAR(str, tok);
+               if (!PEEK_CHAR(c, tok))
+               {
+                       /* out of input chars, for now at least */
+                       goto out;
                }
-       } else {
-               tok->err = json_tokener_error_parse_unexpected;
-               goto out;
        }
-       tok->st_pos++;
+       /* We checked the full length of "Infinity", so create the object.
+        * When handling -Infinity, the number parsing code will have dropped
+        * the "-" into tok->pb for us, so check it now.
+        */
+       if (printbuf_length(tok->pb) > 0 && *(tok->pb->buf) == '-')
+       {
+               is_negative = 1;
+       }
+       current = json_object_new_double(is_negative
+                                        ? -INFINITY : INFINITY);
+       if (current == NULL)
+               goto out;
+       saved_state = json_tokener_state_finish;
+       state = json_tokener_state_eatws;
+       goto redo_char;
+        
       }
       break;
     case json_tokener_state_null: /* aka starts with 'n' */
@@ -934,7 +950,7 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
     }
     if (!ADVANCE_CHAR(str, tok))
       goto out;
-  } /* while(POP_CHAR) */
+  } /* while(PEEK_CHAR) */
 
  out:
   if (c &&