Compare commits

...

11 Commits

Author SHA1 Message Date
Nicolas Badoux
12c4bf1986 Wrong counter increment 2024-09-23 19:08:58 +08:00
Nicolas Badoux
9d1b229086 Added max recusrion depth for cJSONDuplicate to prevent stack exhaustion in case of circular reference 2024-09-23 19:08:58 +08:00
Nicolas Badoux
078c4e6c53 Free mem in cjson_set_valuestring_should_return_null_if_strings_overlap 2024-08-30 11:29:28 +08:00
Nicolas Badoux
4f4d7f70c2 CJSON_SetValuestring: better test for overlapping string 2024-08-30 11:29:28 +08:00
Nicolas Badoux
b47edc4750 CJSON_SetValuestring: add test for overlapping string 2024-08-30 11:29:28 +08:00
Nicolas Badoux
d6d5449e1f fix #881, check overlap before calling strcpy in cJSON_SetValuestring 2024-08-30 11:29:28 +08:00
Nicolas Badoux
a78d975537 cJSON_DetachItemViaPointer: added test and fix for check for null in item->prev 2024-08-30 11:29:05 +08:00
Nicolas Badoux
f28a468e3b Check for NULL in cJSON_DetachItemViaPointer 2024-08-30 11:29:05 +08:00
Alanscut
424ce4ce96 Revert "feat: add tests for #842" to fix test failures
This reverts commit 5b502cdbfb.

Related to #860
2024-06-19 10:58:01 +08:00
Shaun Case
324973008c Fix spelling errors found by CodeSpell. See https://github.com/codespell-project/codespell 2024-05-14 09:43:59 +08:00
DL6ER
8a334b0140 Fix indentation (should use spaces)
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-05-14 09:42:46 +08:00
11 changed files with 94 additions and 33 deletions

35
cJSON.c
View File

@@ -403,6 +403,8 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
{ {
char *copy = NULL; char *copy = NULL;
size_t v1_len;
size_t v2_len;
/* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
if ((object == NULL) || !(object->type & cJSON_String) || (object->type & cJSON_IsReference)) if ((object == NULL) || !(object->type & cJSON_String) || (object->type & cJSON_IsReference))
{ {
@@ -413,8 +415,17 @@ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
{ {
return NULL; return NULL;
} }
if (strlen(valuestring) <= strlen(object->valuestring))
v1_len = strlen(valuestring);
v2_len = strlen(object->valuestring);
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); strcpy(object->valuestring, valuestring);
return object->valuestring; return object->valuestring;
} }
@@ -570,10 +581,10 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out
{ {
length = sprintf((char*)number_buffer, "null"); length = sprintf((char*)number_buffer, "null");
} }
else if(d == (double)item->valueint) else if(d == (double)item->valueint)
{ {
length = sprintf((char*)number_buffer, "%d", item->valueint); length = sprintf((char*)number_buffer, "%d", item->valueint);
} }
else else
{ {
/* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
@@ -2204,7 +2215,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * c
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
{ {
if ((parent == NULL) || (item == NULL)) if ((parent == NULL) || (item == NULL) || (item != parent->child && item->prev == NULL))
{ {
return NULL; return NULL;
} }
@@ -2726,7 +2737,14 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int co
} }
/* Duplication */ /* Duplication */
cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse);
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
{
return cJSON_Duplicate_rec(item, 0, recurse );
}
cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse)
{ {
cJSON *newitem = NULL; cJSON *newitem = NULL;
cJSON *child = NULL; cJSON *child = NULL;
@@ -2773,7 +2791,10 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
child = item->child; child = item->child;
while (child != NULL) while (child != NULL)
{ {
newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ if(depth >= CJSON_CIRCULAR_LIMIT) {
goto fail;
}
newchild = cJSON_Duplicate_rec(child, depth + 1, true); /* Duplicate (with recurse) each item in the ->next chain */
if (!newchild) if (!newchild)
{ {
goto fail; goto fail;

View File

@@ -137,6 +137,12 @@ typedef int cJSON_bool;
#define CJSON_NESTING_LIMIT 1000 #define CJSON_NESTING_LIMIT 1000
#endif #endif
/* Limits the length of circular references can be before cJSON rejects to parse them.
* This is to prevent stack overflows. */
#ifndef CJSON_CIRCULAR_LIMIT
#define CJSON_CIRCULAR_LIMIT 10000
#endif
/* returns the version of cJSON as a string */ /* returns the version of cJSON as a string */
CJSON_PUBLIC(const char*) cJSON_Version(void); CJSON_PUBLIC(const char*) cJSON_Version(void);

View File

@@ -62,7 +62,6 @@ if(ENABLE_CJSON_TEST)
option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.") option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.")
if (ENABLE_VALGRIND) if (ENABLE_VALGRIND)
add_compile_definitions(ENABLE_VALGRIND)
find_program(MEMORYCHECK_COMMAND valgrind) find_program(MEMORYCHECK_COMMAND valgrind)
if ("${MEMORYCHECK_COMMAND}" MATCHES "MEMORYCHECK_COMMAND-NOTFOUND") if ("${MEMORYCHECK_COMMAND}" MATCHES "MEMORYCHECK_COMMAND-NOTFOUND")
message(WARNING "Valgrind couldn't be found.") message(WARNING "Valgrind couldn't be found.")

View File

@@ -34,7 +34,7 @@ static void * CJSON_CDECL failing_malloc(size_t size)
return NULL; return NULL;
} }
/* work around MSVC error C2322: '...' address of dillimport '...' is not static */ /* work around MSVC error C2322: '...' address of dllimport '...' is not static */
static void CJSON_CDECL normal_free(void *pointer) static void CJSON_CDECL normal_free(void *pointer)
{ {
free(pointer); free(pointer);

View File

@@ -219,6 +219,23 @@ static void cjson_should_not_parse_to_deeply_nested_jsons(void)
TEST_ASSERT_NULL_MESSAGE(cJSON_Parse(deep_json), "To deep JSONs should not be parsed."); TEST_ASSERT_NULL_MESSAGE(cJSON_Parse(deep_json), "To deep JSONs should not be parsed.");
} }
static void cjson_should_not_follow_too_deep_circular_references(void)
{
cJSON *o = cJSON_CreateArray();
cJSON *a = cJSON_CreateArray();
cJSON *b = cJSON_CreateArray();
cJSON *x;
cJSON_AddItemToArray(o, a);
cJSON_AddItemToArray(a, b);
cJSON_AddItemToArray(b, o);
x = cJSON_Duplicate(o, 1);
TEST_ASSERT_NULL(x);
cJSON_DetachItemFromArray(b, 0);
cJSON_Delete(o);
}
static void cjson_set_number_value_should_set_numbers(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, NULL}};
@@ -280,6 +297,21 @@ static void cjson_detach_item_via_pointer_should_detach_items(void)
TEST_ASSERT_NULL_MESSAGE(parent->child, "Child of the parent wasn't set to NULL."); TEST_ASSERT_NULL_MESSAGE(parent->child, "Child of the parent wasn't set to NULL.");
} }
static void cjson_detach_item_via_pointer_should_return_null_if_item_prev_is_null(void)
{
cJSON list[2];
cJSON parent[1];
memset(list, '\0', sizeof(list));
/* link the list */
list[0].next = &(list[1]);
parent->child = &list[0];
TEST_ASSERT_NULL_MESSAGE(cJSON_DetachItemViaPointer(parent, &(list[1])), "Failed to detach in the middle.");
TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &(list[0])) == &(list[0]), "Failed to detach in the middle.");
}
static void cjson_replace_item_via_pointer_should_replace_items(void) static void cjson_replace_item_via_pointer_should_replace_items(void)
{ {
cJSON replacements[3]; cJSON replacements[3];
@@ -456,6 +488,24 @@ static void cjson_functions_should_not_crash_with_null_pointers(void)
cJSON_Delete(item); cJSON_Delete(item);
} }
static void cjson_set_valuestring_should_return_null_if_strings_overlap(void)
{
cJSON *obj;
char* str;
char* str2;
obj = cJSON_Parse("\"foo0z\"");
str = cJSON_SetValuestring(obj, "abcde");
str += 1;
/* The string passed to strcpy overlap which is not allowed.*/
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);
cJSON_Delete(obj);
}
static void *CJSON_CDECL failing_realloc(void *pointer, size_t size) static void *CJSON_CDECL failing_realloc(void *pointer, size_t size)
{ {
(void)size; (void)size;
@@ -732,23 +782,6 @@ static void cjson_set_bool_value_must_not_break_objects(void)
cJSON_Delete(sobj); cJSON_Delete(sobj);
} }
static void deallocated_pointers_should_be_set_to_null(void)
{
/* deallocated pointers should be set to null */
/* however, valgrind on linux reports when attempting to access a freed memory, we have to skip it */
#ifndef ENABLE_VALGRIND
cJSON *string = cJSON_CreateString("item");
cJSON *root = cJSON_CreateObject();
cJSON_Delete(string);
free(string->valuestring);
cJSON_AddObjectToObject(root, "object");
cJSON_Delete(root->child);
free(root->child->string);
#endif
}
int CJSON_CDECL main(void) int CJSON_CDECL main(void)
{ {
UNITY_BEGIN(); UNITY_BEGIN();
@@ -761,11 +794,14 @@ int CJSON_CDECL main(void)
RUN_TEST(cjson_get_object_item_case_sensitive_should_not_crash_with_array); RUN_TEST(cjson_get_object_item_case_sensitive_should_not_crash_with_array);
RUN_TEST(typecheck_functions_should_check_type); RUN_TEST(typecheck_functions_should_check_type);
RUN_TEST(cjson_should_not_parse_to_deeply_nested_jsons); RUN_TEST(cjson_should_not_parse_to_deeply_nested_jsons);
RUN_TEST(cjson_should_not_follow_too_deep_circular_references);
RUN_TEST(cjson_set_number_value_should_set_numbers); RUN_TEST(cjson_set_number_value_should_set_numbers);
RUN_TEST(cjson_detach_item_via_pointer_should_detach_items); RUN_TEST(cjson_detach_item_via_pointer_should_detach_items);
RUN_TEST(cjson_detach_item_via_pointer_should_return_null_if_item_prev_is_null);
RUN_TEST(cjson_replace_item_via_pointer_should_replace_items); RUN_TEST(cjson_replace_item_via_pointer_should_replace_items);
RUN_TEST(cjson_replace_item_in_object_should_preserve_name); RUN_TEST(cjson_replace_item_in_object_should_preserve_name);
RUN_TEST(cjson_functions_should_not_crash_with_null_pointers); RUN_TEST(cjson_functions_should_not_crash_with_null_pointers);
RUN_TEST(cjson_set_valuestring_should_return_null_if_strings_overlap);
RUN_TEST(ensure_should_fail_on_failed_realloc); RUN_TEST(ensure_should_fail_on_failed_realloc);
RUN_TEST(skip_utf8_bom_should_skip_bom); RUN_TEST(skip_utf8_bom_should_skip_bom);
RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning);
@@ -779,7 +815,6 @@ int CJSON_CDECL main(void)
RUN_TEST(cjson_delete_item_from_array_should_not_broken_list_structure); RUN_TEST(cjson_delete_item_from_array_should_not_broken_list_structure);
RUN_TEST(cjson_set_valuestring_to_object_should_not_leak_memory); RUN_TEST(cjson_set_valuestring_to_object_should_not_leak_memory);
RUN_TEST(cjson_set_bool_value_must_not_break_objects); RUN_TEST(cjson_set_bool_value_must_not_break_objects);
RUN_TEST(deallocated_pointers_should_be_set_to_null);
return UNITY_END(); return UNITY_END();
} }

View File

@@ -63,7 +63,7 @@ static void assert_print_object(const char * const expected, const char * const
formatted_buffer.format = true; formatted_buffer.format = true;
TEST_ASSERT_TRUE_MESSAGE(print_object(item, &formatted_buffer), "Failed to print formatted string."); TEST_ASSERT_TRUE_MESSAGE(print_object(item, &formatted_buffer), "Failed to print formatted string.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted ojbect is not correct."); TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed_formatted, "Formatted object is not correct.");
reset(item); reset(item);
} }

View File

@@ -78,7 +78,7 @@ class ParseOutput
@array_list.push ' <testcase classname="' + test_suite + '" name="' + test_name + '"/>' @array_list.push ' <testcase classname="' + test_suite + '" name="' + test_name + '"/>'
end end
# Test was flagged as being ingored so format the output # Test was flagged as being ignored so format the output
def test_ignored(array) def test_ignored(array)
last_item = array.length - 1 last_item = array.length - 1
test_name = array[last_item - 2] test_name = array[last_item - 2]

View File

@@ -72,7 +72,7 @@ header files. These three files _are_ Unity.
into this folder already. This is where all the handy documentation can be into this folder already. This is where all the handy documentation can be
found. found.
- `examples` - This contains a few examples of using Unity. - `examples` - This contains a few examples of using Unity.
- `extras` - These are optional add ons to Unity that are not part of the core - `extras` - These are optional addons to Unity that are not part of the core
project. If you've reached us through James Grenning's book, you're going to project. If you've reached us through James Grenning's book, you're going to
want to look here. want to look here.
- `test` - This is how Unity and its scripts are all tested. If you're just using - `test` - This is how Unity and its scripts are all tested. If you're just using

View File

@@ -2,7 +2,7 @@ Eclipse error parsers
===================== =====================
These are a godsend for extracting & quickly navigating to These are a godsend for extracting & quickly navigating to
warnings & error messages from console output. Unforunately warnings & error messages from console output. Unfortunately
I don't know how to write an Eclipse plugin so you'll have I don't know how to write an Eclipse plugin so you'll have
to add them manually. to add them manually.

View File

@@ -8,7 +8,7 @@
#include "unity.h" #include "unity.h"
#include <stddef.h> #include <stddef.h>
/* If omitted from header, declare overrideable prototypes here so they're ready for use */ /* If omitted from header, declare overridable prototypes here so they're ready for use */
#ifdef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION #ifdef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION
void UNITY_OUTPUT_CHAR(int); void UNITY_OUTPUT_CHAR(int);
#endif #endif

View File

@@ -26,7 +26,7 @@ task :prepare_for_tests => TEMP_DIRS
include RakefileHelpers include RakefileHelpers
# Load proper GCC as defult configuration # Load proper GCC as default configuration
DEFAULT_CONFIG_FILE = 'gcc_auto_stdint.yml' DEFAULT_CONFIG_FILE = 'gcc_auto_stdint.yml'
configure_toolchain(DEFAULT_CONFIG_FILE) configure_toolchain(DEFAULT_CONFIG_FILE)