diff --git a/cJSON.c b/cJSON.c index 0568c05..3ccdac2 100644 --- a/cJSON.c +++ b/cJSON.c @@ -662,17 +662,17 @@ fail: } /* Parse the input text into an unescaped cinput, and populate item. */ -static const unsigned char *parse_string(cJSON * const item, const unsigned char * const input, const unsigned char ** const error_pointer, const internal_hooks * const hooks) +static const unsigned char *parse_string(cJSON * const item, parse_buffer * const input_buffer, const unsigned char ** const error_pointer, const internal_hooks * const hooks) { - const unsigned char *input_pointer = input + 1; - const unsigned char *input_end = input + 1; + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; unsigned char *output_pointer = NULL; unsigned char *output = NULL; /* not a string */ - if (*input != '\"') + if (buffer_at_offset(input_buffer)[0] != '\"') { - *error_pointer = input; + *error_pointer = buffer_at_offset(input_buffer); goto fail; } @@ -680,12 +680,12 @@ static const unsigned char *parse_string(cJSON * const item, const unsigned char /* calculate approximate size of the output (overestimate) */ size_t allocation_length = 0; size_t skipped_bytes = 0; - while ((*input_end != '\"') && (*input_end != '\0')) + while ((*input_end != '\"') && ((size_t)(input_end - input_buffer->content) < input_buffer->length)) { /* is escape sequence */ if (input_end[0] == '\\') { - if (input_end[1] == '\0') + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) { /* prevent buffer overflow when last input character is a backslash */ goto fail; @@ -695,13 +695,13 @@ static const unsigned char *parse_string(cJSON * const item, const unsigned char } input_end++; } - if (*input_end == '\0') + if (*input_end != '\"') { goto fail; /* string ended unexpectedly */ } /* This is at most how much we need for the output */ - allocation_length = (size_t) (input_end - input) - skipped_bytes; + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; output = (unsigned char*)hooks->allocate(allocation_length + sizeof("")); if (output == NULL) { @@ -721,6 +721,11 @@ static const unsigned char *parse_string(cJSON * const item, const unsigned char else { unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + switch (input_pointer[1]) { case 'b': @@ -768,7 +773,10 @@ static const unsigned char *parse_string(cJSON * const item, const unsigned char item->type = cJSON_String; item->valuestring = (char*)output; - return input_end + 1; + input_buffer->offset = (size_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return buffer_at_offset(input_buffer); fail: if (output != NULL) @@ -1141,14 +1149,7 @@ static const unsigned char *parse_value(cJSON * const item, parse_buffer * cons /* string */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) { - content_pointer = parse_string(item, buffer_at_offset(input_buffer), error_pointer, hooks); - if (content_pointer == NULL) - { - return NULL; - } - - input_buffer->offset = (size_t)(content_pointer - input_buffer->content); - return buffer_at_offset(input_buffer); + return content_pointer = parse_string(item, input_buffer, error_pointer, hooks); } /* number */ if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) @@ -1422,7 +1423,6 @@ static const unsigned char *parse_object(cJSON * const item, parse_buffer * cons { cJSON *head = NULL; /* linked list head */ cJSON *current_item = NULL; - const unsigned char *content_pointer = NULL; if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) { @@ -1474,12 +1474,10 @@ static const unsigned char *parse_object(cJSON * const item, parse_buffer * cons /* parse the name of the child */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); - content_pointer = parse_string(current_item, buffer_at_offset(input_buffer), error_pointer, hooks); - if (content_pointer == NULL) + if (parse_string(current_item, input_buffer, error_pointer, hooks) == NULL) { goto fail; /* faile to parse name */ } - input_buffer->offset = (size_t)(content_pointer - input_buffer->content); buffer_skip_whitespace(input_buffer); /* swap valuestring and string, because we parsed the name */ diff --git a/tests/parse_string.c b/tests/parse_string.c index f1352a0..9709844 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -47,16 +47,28 @@ static void assert_is_string(cJSON *string_item) static void assert_parse_string(const char *string, const char *expected) { - TEST_ASSERT_NOT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer, &global_hooks), "Couldn't parse string."); + parse_buffer buffer; + buffer.content = (const unsigned char*)string; + buffer.length = strlen(string) + sizeof(""); + buffer.offset = 0; + + TEST_ASSERT_NOT_NULL_MESSAGE(parse_string(item, &buffer, &error_pointer, &global_hooks), "Couldn't parse string."); assert_is_string(item); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, item->valuestring, "The parsed result isn't as expected."); global_hooks.deallocate(item->valuestring); item->valuestring = NULL; } -#define assert_not_parse_string(string) \ - TEST_ASSERT_NULL_MESSAGE(parse_string(item, (const unsigned char*)string, &error_pointer, &global_hooks), "Malformed string should not be accepted");\ - assert_is_invalid(item) +static void assert_not_parse_string(const char * const string) +{ + parse_buffer buffer; + buffer.content = (const unsigned char*)string; + buffer.length = strlen(string) + sizeof(""); + buffer.offset = 0; + + TEST_ASSERT_NULL_MESSAGE(parse_string(item, &buffer, &error_pointer, &global_hooks), "Malformed string should not be accepted."); + assert_is_invalid(item); +}