Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "valuestringlen" to handle null characters in "valuestring". #905

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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