Skip to content

Commit

Permalink
"\u0000" is pretty valid in JSON string. Add valuestringlen to handle…
Browse files Browse the repository at this point in the history
… them in value.

Signed-off-by: He Xian <[email protected]>
  • Loading branch information
hexian000 committed Nov 16, 2024
1 parent 12c4bf1 commit 6f9d1f7
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 28 deletions.
104 changes: 83 additions & 21 deletions cJSON.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,20 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
return item->valuestring;
}

CJSON_PUBLIC(char *) cJSON_GetStringValueWithLength(const cJSON * const item, size_t *length)
{
if (!cJSON_IsString(item))
{
return NULL;
}

if(length != NULL)
{
*length = item->valuestringlen;
}
return item->valuestring;
}

CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
{
if (!cJSON_IsNumber(item))
Expand Down Expand Up @@ -206,6 +220,26 @@ static unsigned char* cJSON_strdup(const unsigned char* string, const internal_h
return copy;
}

static unsigned char* cJSON_strndup(const unsigned char* string, size_t length, const internal_hooks * const hooks)
{
unsigned char *copy = NULL;

if (string == NULL)
{
return NULL;
}

length += sizeof("");
copy = (unsigned char*)hooks->allocate(length);
if (copy == NULL)
{
return NULL;
}
memcpy(copy, string, length);

return copy;
}

CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
{
if (hooks == NULL)
Expand Down Expand Up @@ -401,6 +435,15 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)

/* Note: when passing a NULL valuestring, cJSON_SetValuestring treats this as an error and return NULL */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
{
if (valuestring == NULL)
{
return NULL;
}
return cJSON_SetValuestringWithLength(object, valuestring, strlen(valuestring));
}

CJSON_PUBLIC(char*) cJSON_SetValuestringWithLength(cJSON *object, const char *valuestring, size_t valuestringlen)
{
char *copy = NULL;
size_t v1_len;
Expand All @@ -416,20 +459,18 @@ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
return NULL;
}

v1_len = strlen(valuestring);
v2_len = strlen(object->valuestring);
v1_len = valuestringlen;
v2_len = object->valuestringlen;

if (v1_len <= v2_len)
{
/* strcpy does not handle overlapping string: [X1, X2] [Y1, Y2] => X2 < Y1 or Y2 < X1 */
if (!( valuestring + v1_len < object->valuestring || object->valuestring + v2_len < valuestring ))
{
return NULL;
}
strcpy(object->valuestring, valuestring);
/* memmove does handle overlapping string */
memmove(object->valuestring, valuestring, valuestringlen);
object->valuestring[valuestringlen] = '\0';
object->valuestringlen = valuestringlen;
return object->valuestring;
}
copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
copy = (char*) cJSON_strndup((const unsigned char*)valuestring, valuestringlen, &global_hooks);
if (copy == NULL)
{
return NULL;
Expand All @@ -439,6 +480,7 @@ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
cJSON_free(object->valuestring);
}
object->valuestring = copy;
object->valuestringlen = valuestringlen;

return copy;
}
Expand Down Expand Up @@ -897,6 +939,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu

item->type = cJSON_String;
item->valuestring = (char*)output;
item->valuestringlen = (size_t) (output_pointer - output);

input_buffer->offset = (size_t) (input_end - input_buffer->content);
input_buffer->offset++;
Expand All @@ -918,10 +961,10 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu
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)
static cJSON_bool print_string_len(const unsigned char * const input, const size_t input_length, printbuffer * const output_buffer)
{
const unsigned char *input_pointer = NULL;
const unsigned char * const input_end = input + input_length;
unsigned char *output = NULL;
unsigned char *output_pointer = NULL;
size_t output_length = 0;
Expand All @@ -947,7 +990,7 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe
}

/* set "flag" to 1 if something needs to be escaped */
for (input_pointer = input; *input_pointer; input_pointer++)
for (input_pointer = input; input_pointer < input_end; input_pointer++)
{
switch (*input_pointer)
{
Expand Down Expand Up @@ -992,7 +1035,7 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe
output[0] = '\"';
output_pointer = output + 1;
/* copy the string */
for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
for (input_pointer = input; input_pointer < input_end; (void)input_pointer++, output_pointer++)
{
if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
{
Expand Down Expand Up @@ -1040,10 +1083,16 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe
return true;
}

/* Invoke print_string_ptr (which is useful) on an item. */
/* Render the cstring provided to an escaped version that can be printed. */
static cJSON_bool print_string_ptr(const char * const input, printbuffer * const output_buffer)
{
return print_string_len((const unsigned char*)input, input ? strlen(input) : 0, output_buffer);
}

/* Invoke print_string_len (which is useful) on an item. */
static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
{
return print_string_ptr((unsigned char*)item->valuestring, p);
return print_string_len((unsigned char*)item->valuestring, item->valuestringlen, p);
}

/* Predeclare these prototypes. */
Expand Down Expand Up @@ -1437,7 +1486,7 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp
return false;
}

raw_length = strlen(item->valuestring) + sizeof("");
raw_length = item->valuestringlen + sizeof("");
output = ensure(output_buffer, raw_length);
if (output == NULL)
{
Expand Down Expand Up @@ -1785,7 +1834,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out
}

/* print key */
if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
if (!print_string_ptr(current_item->string, output_buffer))
{
return false;
}
Expand Down Expand Up @@ -2487,12 +2536,18 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
}

CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
{
return cJSON_CreateStringWithLength(string, string ? strlen(string) : 0);
}

CJSON_PUBLIC(cJSON *) cJSON_CreateStringWithLength(const char *string, size_t length)
{
cJSON *item = cJSON_New_Item(&global_hooks);
if(item)
{
item->type = cJSON_String;
item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
item->valuestringlen = length;
item->valuestring = (char*)cJSON_strndup((const unsigned char*)string, length, &global_hooks);
if(!item->valuestring)
{
cJSON_Delete(item);
Expand All @@ -2510,6 +2565,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
{
item->type = cJSON_String | cJSON_IsReference;
item->valuestring = (char*)cast_away_const(string);
item->valuestringlen = strlen(string);
}

return item;
Expand Down Expand Up @@ -2542,7 +2598,8 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
if(item)
{
item->type = cJSON_Raw;
item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
item->valuestringlen = raw ? strlen(raw) : 0;
item->valuestring = (char*)cJSON_strndup((const unsigned char*)raw, item->valuestringlen, &global_hooks);
if(!item->valuestring)
{
cJSON_Delete(item);
Expand Down Expand Up @@ -2768,7 +2825,8 @@ cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse)
newitem->valuedouble = item->valuedouble;
if (item->valuestring)
{
newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
newitem->valuestringlen = item->valuestringlen;
newitem->valuestring = (char*)cJSON_strndup((unsigned char*)item->valuestring, item->valuestringlen, &global_hooks);
if (!newitem->valuestring)
{
goto fail;
Expand Down Expand Up @@ -3078,7 +3136,11 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons
{
return false;
}
if (strcmp(a->valuestring, b->valuestring) == 0)
if (a->valuestringlen != b->valuestringlen)
{
return false;
}
if (memcmp(a->valuestring, b->valuestring, a->valuestringlen) == 0)
{
return true;
}
Expand Down
5 changes: 5 additions & 0 deletions cJSON.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ typedef struct cJSON

/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* Length of the item's string, useful for handling "\u0000" in string */
size_t valuestringlen;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
Expand Down Expand Up @@ -183,6 +185,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);

/* Check item type and return its value */
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
CJSON_PUBLIC(char *) cJSON_GetStringValueWithLength(const cJSON * const item, size_t *length);
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);

/* These functions check the type of an item */
Expand All @@ -204,6 +207,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringWithLength(const char *string, size_t length);
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
Expand Down Expand Up @@ -284,6 +288,7 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
CJSON_PUBLIC(char*) cJSON_SetValuestringWithLength(cJSON *object, const char *valuestring, size_t valuestringlen);

/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
#define cJSON_SetBoolValue(object, boolValue) ( \
Expand Down
11 changes: 5 additions & 6 deletions tests/misc_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ static void cjson_should_not_follow_too_deep_circular_references(void)

static void cjson_set_number_value_should_set_numbers(void)
{
cJSON number[1] = {{NULL, NULL, NULL, cJSON_Number, NULL, 0, 0, NULL}};
cJSON number[1] = {{NULL, NULL, NULL, cJSON_Number, NULL, 0, 0, 0, NULL}};

cJSON_SetNumberValue(number, 1.5);
TEST_ASSERT_EQUAL(1, number->valueint);
Expand Down Expand Up @@ -360,7 +360,7 @@ static void cjson_replace_item_via_pointer_should_replace_items(void)

static void cjson_replace_item_in_object_should_preserve_name(void)
{
cJSON root[1] = {{NULL, NULL, NULL, 0, NULL, 0, 0, NULL}};
cJSON root[1] = {{NULL, NULL, NULL, 0, NULL, 0, 0, 0, NULL}};
cJSON *child = NULL;
cJSON *replacement = NULL;
cJSON_bool flag = false;
Expand Down Expand Up @@ -498,11 +498,10 @@ static void cjson_set_valuestring_should_return_null_if_strings_overlap(void)

str = cJSON_SetValuestring(obj, "abcde");
str += 1;
/* The string passed to strcpy overlap which is not allowed.*/
/* The string passed to strcpy overlap which is correctly copied.*/
str2 = cJSON_SetValuestring(obj, str);
/* If it overlaps, the string will be messed up.*/
TEST_ASSERT_TRUE(strcmp(str, "bcde") == 0);
TEST_ASSERT_NULL(str2);
/* If it overlaps, the string will not be messed up.*/
TEST_ASSERT_TRUE(strncmp(str2, "bcde", 4) == 0);
cJSON_Delete(obj);
}

Expand Down
2 changes: 1 addition & 1 deletion tests/print_string.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ static void assert_print_string(const char *expected, const char *input)
buffer.noalloc = true;
buffer.hooks = global_hooks;

TEST_ASSERT_TRUE_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer), "Failed to print string.");
TEST_ASSERT_TRUE_MESSAGE(print_string_ptr(input, &buffer), "Failed to print string.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed, "The printed string isn't as expected.");
}

Expand Down

0 comments on commit 6f9d1f7

Please sign in to comment.