diff --git a/cJSON.c b/cJSON.c index 3dcde3d..cf48ac9 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1895,32 +1895,37 @@ static void* cast_away_const(const void* string) static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) { + char *new_key = NULL; + int new_type = cJSON_Invalid; + if ((object == NULL) || (string == NULL) || (item == NULL)) { return false; } + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { hooks->deallocate(item->string); } - if (constant_key) - { - item->string = (char*)cast_away_const(string); - item->type |= cJSON_StringIsConst; - } - else - { - char *key = (char*)cJSON_strdup((const unsigned char*)string, hooks); - if (key == NULL) - { - return false; - } - - item->string = key; - item->type &= ~cJSON_StringIsConst; - } + item->string = new_key; + item->type = new_type; return add_item_to_array(object, item); } diff --git a/tests/misc_tests.c b/tests/misc_tests.c index a900e8f..a0b4f7e 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -508,6 +508,25 @@ static void cjson_create_array_reference_should_create_an_array_reference(void) cJSON_Delete(number_reference); } +static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased(void) +{ + cJSON *object = cJSON_CreateObject(); + cJSON *number = cJSON_CreateNumber(42); + char *name = (char*)cJSON_strdup((const unsigned char*)"number", &global_hooks); + + TEST_ASSERT_NOT_NULL(object); + TEST_ASSERT_NOT_NULL(number); + TEST_ASSERT_NOT_NULL(name); + + number->string = name; + + /* The following should not have a use after free + * that would show up in valgrind or with AddressSanitizer */ + cJSON_AddItemToObject(object, number->string, number); + + cJSON_Delete(object); +} + int main(void) { UNITY_BEGIN(); @@ -530,6 +549,7 @@ int main(void) RUN_TEST(cjson_create_string_reference_should_create_a_string_reference); RUN_TEST(cjson_create_object_reference_should_create_an_object_reference); RUN_TEST(cjson_create_array_reference_should_create_an_array_reference); + RUN_TEST(cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased); return UNITY_END(); }