"success",
"continue",
"nesting too deep",
+ "out of memory",
"unexpected end of data",
"unexpected character",
"null expected",
/* ADVANCE_CHAR() macro:
* Increments str & tok->char_offset.
- * For convenience of existing conditionals, returns the old value of c (0 on eof)
+ * For convenience of existing conditionals, returns the old value of c (0 on eof).
* Implicit inputs: c var
*/
#define ADVANCE_CHAR(str, tok) (++(str), ((tok)->char_offset)++, c)
+/* printbuf_memappend_checked(p, s, l) macro:
+ * Add string s of length l to printbuffer p.
+ * If operation fails abort parse operation with memory error.
+ */
+#define printbuf_memappend_checked(p, s, l) \
+ do { \
+ if (printbuf_memappend((p), (s), (l)) < 0) \
+ { \
+ tok->err = json_tokener_error_memory; \
+ goto out; \
+ } \
+ } while (0)
+
/* End optimization macro defs */
struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *str, int len)
char *tmplocale;
tmplocale = setlocale(LC_NUMERIC, NULL);
if (tmplocale)
+ {
oldlocale = strdup(tmplocale);
+ if (oldlocale == NULL)
+ return NULL;
+ }
setlocale(LC_NUMERIC, "C");
}
#endif
if (c == '/' && !(tok->flags & JSON_TOKENER_STRICT))
{
printbuf_reset(tok->pb);
- printbuf_memappend_fast(tok->pb, &c, 1);
+ printbuf_memappend_checked(tok->pb, &c, 1);
state = json_tokener_state_comment_start;
}
else
saved_state = json_tokener_state_object_field_start;
current = json_object_new_object();
if (current == NULL)
+ {
+ tok->err = json_tokener_error_memory;
goto out;
+ }
break;
case '[':
state = json_tokener_state_eatws;
saved_state = json_tokener_state_array;
current = json_object_new_array();
if (current == NULL)
+ {
+ tok->err = json_tokener_error_memory;
goto out;
+ }
break;
case 'I':
case 'i':
}
current = json_object_new_double(is_negative ? -INFINITY : INFINITY);
if (current == NULL)
+ {
+ tok->err = json_tokener_error_memory;
goto out;
+ }
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
goto redo_char;
{
int size;
int size_nan;
- printbuf_memappend_fast(tok->pb, &c, 1);
+ printbuf_memappend_checked(tok->pb, &c, 1);
size = json_min(tok->st_pos + 1, json_null_str_len);
size_nan = json_min(tok->st_pos + 1, json_nan_str_len);
if ((!(tok->flags & JSON_TOKENER_STRICT) &&
{
current = json_object_new_double(NAN);
if (current == NULL)
+ {
+ tok->err = json_tokener_error_memory;
goto out;
+ }
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
goto redo_char;
tok->err = json_tokener_error_parse_comment;
goto out;
}
- printbuf_memappend_fast(tok->pb, &c, 1);
+ printbuf_memappend_checked(tok->pb, &c, 1);
break;
case json_tokener_state_comment:
{
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok))
{
- printbuf_memappend_fast(tok->pb, case_start,
- str - case_start);
+ printbuf_memappend_checked(tok->pb, case_start,
+ str - case_start);
goto out;
}
}
- printbuf_memappend_fast(tok->pb, case_start, 1 + str - case_start);
+ printbuf_memappend_checked(tok->pb, case_start, 1 + str - case_start);
state = json_tokener_state_comment_end;
}
break;
{
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok))
{
- printbuf_memappend_fast(tok->pb, case_start,
- str - case_start);
+ printbuf_memappend_checked(tok->pb, case_start,
+ str - case_start);
goto out;
}
}
- printbuf_memappend_fast(tok->pb, case_start, str - case_start);
+ printbuf_memappend_checked(tok->pb, case_start, str - case_start);
MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf);
state = json_tokener_state_eatws;
}
break;
case json_tokener_state_comment_end:
- printbuf_memappend_fast(tok->pb, &c, 1);
+ printbuf_memappend_checked(tok->pb, &c, 1);
if (c == '/')
{
MC_DEBUG("json_tokener_comment: %s\n", tok->pb->buf);
{
if (c == tok->quote_char)
{
- printbuf_memappend_fast(tok->pb, case_start,
- str - case_start);
+ printbuf_memappend_checked(tok->pb, case_start,
+ str - case_start);
current =
json_object_new_string_len(tok->pb->buf, tok->pb->bpos);
if (current == NULL)
+ {
+ tok->err = json_tokener_error_memory;
goto out;
+ }
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
break;
}
else if (c == '\\')
{
- printbuf_memappend_fast(tok->pb, case_start,
- str - case_start);
+ printbuf_memappend_checked(tok->pb, case_start,
+ str - case_start);
saved_state = json_tokener_state_string;
state = json_tokener_state_string_escape;
break;
}
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok))
{
- printbuf_memappend_fast(tok->pb, case_start,
- str - case_start);
+ printbuf_memappend_checked(tok->pb, case_start,
+ str - case_start);
goto out;
}
}
case '"':
case '\\':
case '/':
- printbuf_memappend_fast(tok->pb, &c, 1);
+ printbuf_memappend_checked(tok->pb, &c, 1);
state = saved_state;
break;
case 'b':
case 't':
case 'f':
if (c == 'b')
- printbuf_memappend_fast(tok->pb, "\b", 1);
+ printbuf_memappend_checked(tok->pb, "\b", 1);
else if (c == 'n')
- printbuf_memappend_fast(tok->pb, "\n", 1);
+ printbuf_memappend_checked(tok->pb, "\n", 1);
else if (c == 'r')
- printbuf_memappend_fast(tok->pb, "\r", 1);
+ printbuf_memappend_checked(tok->pb, "\r", 1);
else if (c == 't')
- printbuf_memappend_fast(tok->pb, "\t", 1);
+ printbuf_memappend_checked(tok->pb, "\t", 1);
else if (c == 'f')
- printbuf_memappend_fast(tok->pb, "\f", 1);
+ printbuf_memappend_checked(tok->pb, "\f", 1);
state = saved_state;
break;
case 'u':
/* High surrogate was not followed by a low surrogate
* Replace the high and process the rest normally
*/
- printbuf_memappend_fast(tok->pb,
- (char *)utf8_replacement_char, 3);
+ printbuf_memappend_checked(tok->pb,
+ (char *)utf8_replacement_char, 3);
}
tok->high_surrogate = 0;
}
{
unsigned char unescaped_utf[1];
unescaped_utf[0] = tok->ucs_char;
- printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 1);
+ printbuf_memappend_checked(tok->pb, (char *)unescaped_utf, 1);
}
else if (tok->ucs_char < 0x800)
{
unsigned char unescaped_utf[2];
unescaped_utf[0] = 0xc0 | (tok->ucs_char >> 6);
unescaped_utf[1] = 0x80 | (tok->ucs_char & 0x3f);
- printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 2);
+ printbuf_memappend_checked(tok->pb, (char *)unescaped_utf, 2);
}
else if (IS_HIGH_SURROGATE(tok->ucs_char))
{
else if (IS_LOW_SURROGATE(tok->ucs_char))
{
/* Got a low surrogate not preceded by a high */
- printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3);
+ printbuf_memappend_checked(tok->pb, (char *)utf8_replacement_char, 3);
}
else if (tok->ucs_char < 0x10000)
{
unescaped_utf[0] = 0xe0 | (tok->ucs_char >> 12);
unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
unescaped_utf[2] = 0x80 | (tok->ucs_char & 0x3f);
- printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 3);
+ printbuf_memappend_checked(tok->pb, (char *)unescaped_utf, 3);
}
else if (tok->ucs_char < 0x110000)
{
unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 12) & 0x3f);
unescaped_utf[2] = 0x80 | ((tok->ucs_char >> 6) & 0x3f);
unescaped_utf[3] = 0x80 | (tok->ucs_char & 0x3f);
- printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 4);
+ printbuf_memappend_checked(tok->pb, (char *)unescaped_utf, 4);
}
else
{
/* Don't know what we got--insert the replacement char */
- printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3);
+ printbuf_memappend_checked(tok->pb, (char *)utf8_replacement_char, 3);
}
state = saved_state; // i.e. _state_string or _state_object_field
}
* it. Put a replacement char in for the high surrogate
* and pop back up to _state_string or _state_object_field.
*/
- printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3);
+ printbuf_memappend_checked(tok->pb, (char *)utf8_replacement_char, 3);
tok->high_surrogate = 0;
tok->ucs_char = 0;
tok->st_pos = 0;
* Put a replacement char in for the high surrogate
* and handle the escape sequence normally.
*/
- printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3);
+ printbuf_memappend_checked(tok->pb, (char *)utf8_replacement_char, 3);
tok->high_surrogate = 0;
tok->ucs_char = 0;
tok->st_pos = 0;
case json_tokener_state_boolean:
{
int size1, size2;
- printbuf_memappend_fast(tok->pb, &c, 1);
+ printbuf_memappend_checked(tok->pb, &c, 1);
size1 = json_min(tok->st_pos + 1, json_true_str_len);
size2 = json_min(tok->st_pos + 1, json_false_str_len);
if ((!(tok->flags & JSON_TOKENER_STRICT) &&
{
current = json_object_new_boolean(1);
if (current == NULL)
+ {
+ tok->err = json_tokener_error_memory;
goto out;
+ }
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
goto redo_char;
{
current = json_object_new_boolean(0);
if (current == NULL)
+ {
+ tok->err = json_tokener_error_memory;
goto out;
+ }
saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws;
goto redo_char;
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok))
{
- printbuf_memappend_fast(tok->pb, case_start, case_len);
+ printbuf_memappend_checked(tok->pb, case_start, case_len);
goto out;
}
}
it might have been intended to be, and return a potentially
more understandable error right away.
However, if we're at the top-level, use the number as-is
- because c can be part of a new object to parse on the
+ because c can be part of a new object to parse on the
next call to json_tokener_parse().
*/
if (tok->depth > 0 && c != ',' && c != ']' && c != '}' && c != '/' &&
goto out;
}
if (case_len > 0)
- printbuf_memappend_fast(tok->pb, case_start, case_len);
+ printbuf_memappend_checked(tok->pb, case_start, case_len);
// Check for -Infinity
if (tok->pb->buf[0] == '-' && case_len <= 1 && (c == 'i' || c == 'I'))
{
current = json_object_new_int64(num64);
if (current == NULL)
+ {
+ tok->err = json_tokener_error_memory;
goto out;
+ }
}
else if (!tok->is_double && tok->pb->buf[0] != '-' &&
json_parse_uint64(tok->pb->buf, &numuint64) == 0)
num64 = (uint64_t)numuint64;
current = json_object_new_int64(num64);
if (current == NULL)
+ {
+ tok->err = json_tokener_error_memory;
goto out;
+ }
}
else
{
current = json_object_new_uint64(numuint64);
if (current == NULL)
+ {
+ tok->err = json_tokener_error_memory;
goto out;
+ }
}
}
else if (tok->is_double &&
{
current = json_object_new_double_s(numd, tok->pb->buf);
if (current == NULL)
+ {
+ tok->err = json_tokener_error_memory;
goto out;
+ }
}
else
{
case json_tokener_state_array_add:
if (json_object_array_add(current, obj) != 0)
+ {
+ tok->err = json_tokener_error_memory;
goto out;
+ }
saved_state = json_tokener_state_array_sep;
state = json_tokener_state_eatws;
goto redo_char;
{
if (c == tok->quote_char)
{
- printbuf_memappend_fast(tok->pb, case_start,
- str - case_start);
+ printbuf_memappend_checked(tok->pb, case_start,
+ str - case_start);
obj_field_name = strdup(tok->pb->buf);
+ if (obj_field_name == NULL)
+ {
+ tok->err = json_tokener_error_memory;
+ goto out;
+ }
saved_state = json_tokener_state_object_field_end;
state = json_tokener_state_eatws;
break;
}
else if (c == '\\')
{
- printbuf_memappend_fast(tok->pb, case_start,
- str - case_start);
+ printbuf_memappend_checked(tok->pb, case_start,
+ str - case_start);
saved_state = json_tokener_state_object_field;
state = json_tokener_state_string_escape;
break;
}
if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok))
{
- printbuf_memappend_fast(tok->pb, case_start,
- str - case_start);
+ printbuf_memappend_checked(tok->pb, case_start,
+ str - case_start);
goto out;
}
}