1
0
mirror of https://github.com/DaveGamble/cJSON synced 2025-04-25 20:57:55 +00:00
This commit is contained in:
ljluestc 2025-03-13 20:55:22 -07:00 committed by GitHub
commit 43a56d26f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 40 additions and 24 deletions

37
cJSON.c
View File

@ -796,24 +796,31 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu
unsigned char *output_pointer = NULL;
unsigned char *output = NULL;
/* not a string */
/* Not a string */
if (buffer_at_offset(input_buffer)[0] != '\"')
{
goto fail;
}
{
/* calculate approximate size of the output (overestimate) */
/* Calculate approximate size of the output (overestimate) and validate control characters */
size_t allocation_length = 0;
size_t skipped_bytes = 0;
while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
{
/* is escape sequence */
/* Check for unescaped control characters (U+0000 to U+001F) */
if (*input_end < 0x20) /* Control characters must be escaped */
{
input_buffer->offset = (size_t)(input_end - input_buffer->content);
goto fail; /* Error: unescaped control character */
}
/* Is escape sequence */
if (input_end[0] == '\\')
{
if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
{
/* prevent buffer overflow when last input character is a backslash */
/* Prevent buffer overflow when last input character is a backslash */
goto fail;
}
skipped_bytes++;
@ -823,27 +830,27 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu
}
if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
{
goto fail; /* string ended unexpectedly */
goto fail; /* String ended unexpectedly */
}
/* This is at most how much we need for the output */
allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
if (output == NULL)
{
goto fail; /* allocation failure */
goto fail; /* Allocation failure */
}
}
output_pointer = output;
/* loop through the string literal */
/* Loop through the string literal */
while (input_pointer < input_end)
{
if (*input_pointer != '\\')
{
*output_pointer++ = *input_pointer++;
}
/* escape sequence */
/* Escape sequence */
else
{
unsigned char sequence_length = 2;
@ -880,25 +887,25 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu
sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
if (sequence_length == 0)
{
/* failed to convert UTF16-literal to UTF-8 */
/* Failed to convert UTF16-literal to UTF-8 */
goto fail;
}
break;
default:
goto fail;
goto fail; /* Invalid escape sequence */
}
input_pointer += sequence_length;
}
}
/* zero terminate the output */
/* Zero terminate the output */
*output_pointer = '\0';
item->type = cJSON_String;
item->valuestring = (char*)output;
input_buffer->offset = (size_t) (input_end - input_buffer->content);
input_buffer->offset = (size_t)(input_end - input_buffer->content);
input_buffer->offset++;
return true;
@ -907,10 +914,9 @@ fail:
if (output != NULL)
{
input_buffer->hooks.deallocate(output);
output = NULL;
}
if (input_pointer != NULL)
if (input_pointer != NULL && (size_t)(input_pointer - input_buffer->content) < input_buffer->length)
{
input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
}
@ -918,6 +924,7 @@ fail:
return false;
}
/* Render the cstring provided to an escaped version that can be printed. */
static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
{

View File

@ -33,7 +33,6 @@ static cJSON item[1];
static void assert_is_string(cJSON *string_item)
{
TEST_ASSERT_NOT_NULL_MESSAGE(string_item, "Item is NULL.");
assert_not_in_list(string_item);
assert_has_no_child(string_item);
assert_has_type(string_item, cJSON_String);
@ -68,8 +67,6 @@ static void assert_not_parse_string(const char * const string)
assert_is_invalid(item);
}
static void parse_string_should_parse_strings(void)
{
assert_parse_string("\"\"", "");
@ -77,10 +74,8 @@ static void parse_string_should_parse_strings(void)
"\" !\\\"#$%&'()*+,-./\\/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_'abcdefghijklmnopqrstuvwxyz{|}~\"",
" !\"#$%&'()*+,-.//0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'abcdefghijklmnopqrstuvwxyz{|}~");
assert_parse_string(
"\"\\\"\\\\\\/\\b\\f\\n\\r\\t\\u20AC\\u732b\"",
"\"\\/\b\f\n\r\t€猫");
reset(item);
assert_parse_string("\"\b\f\n\r\t\"", "\b\f\n\r\t");
"\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"",
"\"\\/\b\f\n\r\t");
reset(item);
}
@ -119,9 +114,22 @@ static void parse_string_should_parse_bug_94(void)
reset(item);
}
static void parse_string_should_not_parse_unescaped_control_chars(void)
{
/* Test unescaped control characters (U+0000 to U+001F) */
assert_not_parse_string("\"\x0a\""); /* Newline */
reset(item);
assert_not_parse_string("\"\x00\""); /* Null character */
reset(item);
assert_not_parse_string("\"1\x0a2\""); /* Newline in middle, matches #766 test case */
reset(item);
assert_not_parse_string("\"\x1f\""); /* Unit separator (highest control char) */
reset(item);
}
int CJSON_CDECL main(void)
{
/* initialize cJSON item and error pointer */
/* Initialize cJSON item and error pointer */
memset(item, 0, sizeof(cJSON));
UNITY_BEGIN();
@ -131,5 +139,6 @@ int CJSON_CDECL main(void)
RUN_TEST(parse_string_should_not_parse_invalid_backslash);
RUN_TEST(parse_string_should_parse_bug_94);
RUN_TEST(parse_string_should_not_overflow_with_closing_backslash);
RUN_TEST(parse_string_should_not_parse_unescaped_control_chars); /* New test */
return UNITY_END();
}
}