From 38b44a298d9cebe3a82d808d92d01681eef44bbe Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 4 Jun 2017 19:36:46 +0200 Subject: [PATCH 001/307] Squashed 'tests/unity/' changes from f96c055..3b69bea 3b69bea Merge pull request #284 from rmja/patch-1 aef3679 Fixed UNITY_TEST_ASSERT_EACH_EQUAL_* git-subtree-dir: tests/unity git-subtree-split: 3b69beaa58efc41bbbef70a32a46893cae02719d --- src/unity_internals.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/unity_internals.h b/src/unity_internals.h index cc20ea4f..c08db955 100644 --- a/src/unity_internals.h +++ b/src/unity_internals.h @@ -706,9 +706,9 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64, UNITY_ARRAY_TO_ARRAY) #define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_ARRAY) #define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_INTERNAL_PTR)(expected), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64, UNITY_ARRAY_TO_ARRAY) -#define UNITY_TEST_ASSERT_EACH_EQUAL_INT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64, UNITY_ARRAY_TO_ARRAY) -#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_ARRAY) -#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64, UNITY_ARRAY_TO_ARRAY) +#define UNITY_TEST_ASSERT_EACH_EQUAL_INT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_UINT64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_UINT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64, UNITY_ARRAY_TO_VAL) +#define UNITY_TEST_ASSERT_EACH_EQUAL_HEX64(expected, actual, num_elements, line, message) UnityAssertEqualIntArray(UnityNumToPtr((UNITY_INT)(UNITY_INT64)expected, 8), (UNITY_INTERNAL_PTR)(actual), (UNITY_UINT32)(num_elements), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64, UNITY_ARRAY_TO_VAL) #define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) #define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) #define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) From bfbd8fe0d85f1dd21e508748fc10fc4c27cc51be Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 4 Jun 2017 21:24:28 +0200 Subject: [PATCH 002/307] tests/parse_hex4: Fix GCC 7 compiler warning (fixes #179) --- CMakeLists.txt | 1 + tests/parse_hex4.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 88484de1..b1b705d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) -Wcomma -Wdouble-promotion -Wparentheses + -Wformat-overflow ) endif() diff --git a/tests/parse_hex4.c b/tests/parse_hex4.c index 59b07eec..7115cbae 100644 --- a/tests/parse_hex4.c +++ b/tests/parse_hex4.c @@ -31,8 +31,8 @@ static void parse_hex4_should_parse_all_combinations(void) { unsigned int number = 0; - unsigned char digits_lower[5]; - unsigned char digits_upper[5]; + unsigned char digits_lower[6]; + unsigned char digits_upper[6]; /* test all combinations */ for (number = 0; number <= 0xFFFF; number++) { From 9189b3322aa4ec038aa7311a40da633ae7a9960a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 4 Jun 2017 21:31:45 +0200 Subject: [PATCH 003/307] Release v1.5.4 --- CHANGELOG.md | 10 ++++++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28c250e2..f1625b48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +1.5.4 +===== +Fixes: +------ +* Fix build with GCC 7.1.1 and optimization level `-O2` (bfbd8fe0d85f1dd21e508748fc10fc4c27cc51be) + +Other Changes: +-------------- +* Update [Unity](https://github.com/ThrowTheSwitch/Unity) to 3b69beaa58efc41bbbef70a32a46893cae02719d + 1.5.3 ===== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index b1b705d8..d953ed83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project(cJSON C) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 5) -set(PROJECT_VERSION_PATCH 3) +set(PROJECT_VERSION_PATCH 4) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index b30ab88d..be31b041 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.5.3 +LIBVERSION = 1.5.4 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 2494cd96..0722c8e1 100644 --- a/cJSON.c +++ b/cJSON.c @@ -58,7 +58,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 3) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 4) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index fe622eec..eb16c1e9 100644 --- a/cJSON.h +++ b/cJSON.h @@ -31,7 +31,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 5 -#define CJSON_VERSION_PATCH 3 +#define CJSON_VERSION_PATCH 4 #include From 9abe75e072050f34732a7169740989a082b65134 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 14 Jun 2017 17:20:12 +0200 Subject: [PATCH 004/307] cJSON_Utils: Fix get_item_from_pointer Accessing nested arrays didn't work as intended. --- cJSON_Utils.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 8f99c2e7..bd672017 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -279,16 +279,17 @@ static cJSON *get_item_from_pointer(cJSON * const object, const char * pointer, { current_element = current_element->next; } - /* skip to the next path token or end of string */ - while ((pointer[0] != '\0') && (pointer[0] != '/')) - { - pointer++; - } } else { return NULL; } + + /* skip to the next path token or end of string */ + while ((pointer[0] != '\0') && (pointer[0] != '/')) + { + pointer++; + } } return current_element; From b9cc911831b0b3e1bb72f142389428e59f882b38 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 14 Jun 2017 17:45:44 +0200 Subject: [PATCH 005/307] cJSON_Utils: Fix case sensitivity handling when adding to object --- cJSON_Utils.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index bd672017..c0fd649d 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -943,7 +943,14 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_ } else if (cJSON_IsObject(parent)) { - cJSON_DeleteItemFromObject(parent, (char*)child_pointer); + if (case_sensitive) + { + cJSON_DeleteItemFromObjectCaseSensitive(parent, (char*)child_pointer); + } + else + { + cJSON_DeleteItemFromObject(parent, (char*)child_pointer); + } cJSON_AddItemToObject(parent, (char*)child_pointer, value); value = NULL; } From 569aa060c6319fb24ab21bbf699aad2c40f454c1 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 13 Jun 2017 08:39:18 +0200 Subject: [PATCH 006/307] cJSON_Compare: Fix comparison of arrays It did consider two arrays equal if one is a prefix of the other one, which is incorrect. See #180 --- cJSON.c | 5 +++++ tests/compare_tests.c | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/cJSON.c b/cJSON.c index 0722c8e1..51fded74 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2594,6 +2594,11 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons b_element = b_element->next; } + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + return true; } diff --git a/tests/compare_tests.c b/tests/compare_tests.c index 654e14e7..59842688 100644 --- a/tests/compare_tests.c +++ b/tests/compare_tests.c @@ -148,6 +148,10 @@ static void cjson_compare_should_compare_arrays(void) TEST_ASSERT_FALSE(compare_from_string("[true,null,42,\"string\",[],{}]", "[false, true, null, 42, \"string\", [], {}]", true)); TEST_ASSERT_FALSE(compare_from_string("[true,null,42,\"string\",[],{}]", "[false, true, null, 42, \"string\", [], {}]", false)); + + /* Arrays that are a prefix of another array */ + TEST_ASSERT_FALSE(compare_from_string("[1,2,3]", "[1,2]", true)); + TEST_ASSERT_FALSE(compare_from_string("[1,2,3]", "[1,2]", false)); } static void cjson_compare_should_compare_objects(void) From 03ba72faec115160d1f3aea5582d9b6af5d3e473 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 13 Jun 2017 08:48:41 +0200 Subject: [PATCH 007/307] cJSON_Compare: Fix comparison of objects It did consider two arrays equal if one is a subset of te other one, which is incorrect. See #180 --- cJSON.c | 19 ++++++++++++++++++- tests/compare_tests.c | 9 +++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 51fded74..e32f7ca4 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2605,10 +2605,11 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons case cJSON_Object: { cJSON *a_element = NULL; + cJSON *b_element = NULL; cJSON_ArrayForEach(a_element, a) { /* TODO This has O(n^2) runtime, which is horrible! */ - cJSON *b_element = get_object_item(b, a_element->string, case_sensitive); + b_element = get_object_item(b, a_element->string, case_sensitive); if (b_element == NULL) { return false; @@ -2620,6 +2621,22 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons } } + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + return true; } diff --git a/tests/compare_tests.c b/tests/compare_tests.c index 59842688..63b6d4a0 100644 --- a/tests/compare_tests.c +++ b/tests/compare_tests.c @@ -175,6 +175,15 @@ static void cjson_compare_should_compare_objects(void) "{\"Flse\": false, \"true\": true, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}", "{\"true\": true, \"false\": false, \"null\": null, \"number\": 42, \"string\": \"string\", \"array\": [], \"object\": {}}", false)); + /* test objects that are a subset of each other */ + TEST_ASSERT_FALSE(compare_from_string( + "{\"one\": 1, \"two\": 2}", + "{\"one\": 1, \"two\": 2, \"three\": 3}", + true)) + TEST_ASSERT_FALSE(compare_from_string( + "{\"one\": 1, \"two\": 2}", + "{\"one\": 1, \"two\": 2, \"three\": 3}", + false)) } int main(void) From a2a2411b1296a1c519c615b92d747e9c5df37d1e Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 14 Jun 2017 18:04:19 +0200 Subject: [PATCH 008/307] Release version 1.5.5 --- CHANGELOG.md | 8 ++++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1625b48..3c4e6031 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +1.5.5 +===== +Fixes: +------ +* Fix pointers to nested arrays in cJSON_Utils (9abe75e072050f34732a7169740989a082b65134) +* Fix an error with case sensitivity handling in cJSON_Utils (b9cc911831b0b3e1bb72f142389428e59f882b38) +* Fix cJSON_Compare for arrays that are prefixes of the other and objects that are a subset of the other (03ba72faec115160d1f3aea5582d9b6af5d3e473) See #180, thanks @zhengqb for reporting + 1.5.4 ===== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index d953ed83..2da43a95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project(cJSON C) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 5) -set(PROJECT_VERSION_PATCH 4) +set(PROJECT_VERSION_PATCH 5) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index be31b041..16e7eb75 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.5.4 +LIBVERSION = 1.5.5 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index e32f7ca4..aa6e563d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -58,7 +58,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 4) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 5) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index eb16c1e9..2af0a9c5 100644 --- a/cJSON.h +++ b/cJSON.h @@ -31,7 +31,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 5 -#define CJSON_VERSION_PATCH 4 +#define CJSON_VERSION_PATCH 5 #include From 2a3a313f83c11ee31480a6e4f77a82bfe4662701 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 22:57:19 +0200 Subject: [PATCH 009/307] cJSON_PrintBuffered: Fix potential memory leak --- cJSON.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cJSON.c b/cJSON.c index aa6e563d..4c12f20e 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1111,6 +1111,7 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON if (!print_value(item, &p)) { + global_hooks.deallocate(p.buffer); return NULL; } From 90a46eaccd99cf2980f8bbb3982e98bb26527f23 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 21:58:30 +0200 Subject: [PATCH 010/307] cJSON.h: Move cJSON_ParseWithOpts after cJSON_Parse --- cJSON.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cJSON.h b/cJSON.h index 2af0a9c5..71d8dbb1 100644 --- a/cJSON.h +++ b/cJSON.h @@ -138,6 +138,10 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); + /* Render a cJSON entity to text for transfer/storage. */ CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); /* Render a cJSON entity to text for transfer/storage without any formatting. */ @@ -228,10 +232,6 @@ The item->next and ->prev pointers are always zero on return from Duplicate. */ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); -/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ -/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */ -CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); - CJSON_PUBLIC(void) cJSON_Minify(char *json); /* Macros for creating things quickly. */ From cdc35ebf88c5d440b8f63e9a69412c22c0abb6fa Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 21:34:42 +0200 Subject: [PATCH 011/307] handle null pointers: cJSON_AddItemToObject --- cJSON.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cJSON.c b/cJSON.c index 4c12f20e..16acd420 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1790,6 +1790,11 @@ CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) { + if (item == NULL) + { + return; + } + /* call cJSON_AddItemToObjectCS for code reuse */ cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item); /* remove cJSON_StringIsConst flag */ From 56f2bc6f3e65e15f0b3ca50f59a2104fd30d8e99 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 22:58:25 +0200 Subject: [PATCH 012/307] handle null pointers: cJSON_PrintPreallocated --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 16acd420..80d35db5 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1122,7 +1122,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const i { printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - if (len < 0) + if ((len < 0) || (buf == NULL)) { return false; } From e9d1de24cf69e046b683fc0ae24469231e5249c7 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 22:58:51 +0200 Subject: [PATCH 013/307] handle null pointers: cJSON_GetArraySize --- cJSON.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/cJSON.c b/cJSON.c index 80d35db5..499ec2e9 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1653,17 +1653,25 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out /* Get Array size/item / object item. */ CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) { - cJSON *c = array->child; - size_t i = 0; - while(c) + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) { - i++; - c = c->next; + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; } /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ - return (int)i; + return (int)size; } static cJSON* get_array_item(const cJSON *array, size_t index) From 90ff72c8bbec3786816ca07d4cb8df7fb8a1c0de Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 23:00:19 +0200 Subject: [PATCH 014/307] handle null pointers: create_reference Also fixes a potential memory leak --- cJSON.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/cJSON.c b/cJSON.c index 499ec2e9..3bf109b7 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1756,16 +1756,23 @@ static void suffix_object(cJSON *prev, cJSON *item) /* Utility for handling references. */ static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) { - cJSON *ref = cJSON_New_Item(hooks); - if (!ref) + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) { return NULL; } - memcpy(ref, item, sizeof(cJSON)); - ref->string = NULL; - ref->type |= cJSON_IsReference; - ref->next = ref->prev = NULL; - return ref; + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; } /* Add item to array/object. */ From 46c4f55c94e836ffffc892875549745c9627f2c6 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 23:01:38 +0200 Subject: [PATCH 015/307] handle null pointers: cJSON_AddItemToObjectCS --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 3bf109b7..5d3c4a7b 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1826,7 +1826,7 @@ CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSO /* Add an item to an object with constant string as key */ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) { - if (!item) + if ((item == NULL) || (string == NULL)) { return; } From c179509b31c22c412108c0e076b968e77b9def2c Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 23:02:14 +0200 Subject: [PATCH 016/307] handle null pointers: cJSON_AddItemReferenceToArray --- cJSON.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cJSON.c b/cJSON.c index 5d3c4a7b..2c3f9e65 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1844,6 +1844,11 @@ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJ CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) { + if (array == NULL) + { + return; + } + cJSON_AddItemToArray(array, create_reference(item, &global_hooks)); } From b2fe02712da707009b6e27a9b64387ac39623b63 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 23:03:23 +0200 Subject: [PATCH 017/307] handle null pointers: cJSON_AddItemReferenceToObject --- cJSON.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cJSON.c b/cJSON.c index 2c3f9e65..1e9802aa 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1854,6 +1854,11 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) { + if ((object == NULL) || (string == NULL)) + { + return; + } + cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks)); } From 8ea37fce017847372f5bdd144c380b57c023af5d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 23:03:59 +0200 Subject: [PATCH 018/307] handle null pointers: replace_item_in_object --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 1e9802aa..15bd7f8c 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2008,7 +2008,7 @@ CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newi static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) { - if (replacement == NULL) + if ((replacement == NULL) || (string == NULL)) { return false; } From 010e31f2f259f7627e8dd81023d6df8bb9c125e5 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 23:04:28 +0200 Subject: [PATCH 019/307] handle null pointers: cJSON_CreateIntArray --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 15bd7f8c..6021cad8 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2171,7 +2171,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) cJSON *p = NULL; cJSON *a = NULL; - if (count < 0) + if ((count < 0) || (numbers == NULL)) { return NULL; } From 9f745a2251835ba0fe89d003779323c79f975712 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 23:04:47 +0200 Subject: [PATCH 020/307] handle null pointers: cJSON_CreateFloatArray --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 6021cad8..eff35bc9 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2206,7 +2206,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) cJSON *p = NULL; cJSON *a = NULL; - if (count < 0) + if ((count < 0) || (numbers == NULL)) { return NULL; } From c268e77b21cb0d8fde352473dd7d71b710dd919e Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 23:05:16 +0200 Subject: [PATCH 021/307] handle null pointers: cJSON_CreateDoubleArray --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index eff35bc9..fd83a2d9 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2242,7 +2242,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) cJSON *p = NULL; cJSON *a = NULL; - if (count < 0) + if ((count < 0) || (numbers == NULL)) { return NULL; } From 9585c38d5a79acc12c79aeca0500810870798e35 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 27 Jun 2017 23:05:38 +0200 Subject: [PATCH 022/307] handle null pointers: cJSON_CreateStringArray --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index fd83a2d9..ed2246e2 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2278,7 +2278,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) cJSON *p = NULL; cJSON *a = NULL; - if (count < 0) + if ((count < 0) || (strings == NULL)) { return NULL; } From 39745c9c75025336f94207ddc7bd962f09deee99 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 28 Jun 2017 14:07:25 +0200 Subject: [PATCH 023/307] handle null pointers: cJSON_ReplaceItemViaPointer --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index ed2246e2..b3abfb4c 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1963,7 +1963,7 @@ CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newit CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) { - if ((parent == NULL) || (replacement == NULL)) + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) { return false; } From 24ea388dcf6a9c7974b099de8b648461d9aa96c9 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 28 Jun 2017 14:17:23 +0200 Subject: [PATCH 024/307] handle null pointers: cJSON_Minify --- cJSON.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cJSON.c b/cJSON.c index b3abfb4c..fdc136f3 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2390,6 +2390,12 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) CJSON_PUBLIC(void) cJSON_Minify(char *json) { unsigned char *into = (unsigned char*)json; + + if (json == NULL) + { + return; + } + while (*json) { if (*json == ' ') From bdd5ff7ad652cd4d5b8c5a493178549afda0cc06 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 28 Jun 2017 14:18:39 +0200 Subject: [PATCH 025/307] misc_tests: Call all functions with NULL pointers --- tests/misc_tests.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 9619db2a..7d511793 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -324,6 +324,92 @@ static void cjson_replace_item_in_object_should_preserve_name(void) cJSON_Delete(replacement); } +static void cjson_functions_shouldnt_crash_with_null_pointers(void) +{ + char buffer[10]; + cJSON *item = cJSON_CreateString("item"); + + cJSON_InitHooks(NULL); + TEST_ASSERT_NULL(cJSON_Parse(NULL)); + TEST_ASSERT_NULL(cJSON_ParseWithOpts(NULL, NULL, true)); + TEST_ASSERT_NULL(cJSON_Print(NULL)); + TEST_ASSERT_NULL(cJSON_PrintUnformatted(NULL)); + TEST_ASSERT_NULL(cJSON_PrintBuffered(NULL, 10, true)); + TEST_ASSERT_FALSE(cJSON_PrintPreallocated(NULL, buffer, sizeof(buffer), true)); + TEST_ASSERT_FALSE(cJSON_PrintPreallocated(item, NULL, 1, true)); + cJSON_Delete(NULL); + cJSON_GetArraySize(NULL); + TEST_ASSERT_NULL(cJSON_GetArrayItem(NULL, 0)); + TEST_ASSERT_NULL(cJSON_GetObjectItem(NULL, "item")); + TEST_ASSERT_NULL(cJSON_GetObjectItem(item, NULL)); + TEST_ASSERT_NULL(cJSON_GetObjectItemCaseSensitive(NULL, "item")); + TEST_ASSERT_NULL(cJSON_GetObjectItemCaseSensitive(item, NULL)); + TEST_ASSERT_FALSE(cJSON_HasObjectItem(NULL, "item")); + TEST_ASSERT_FALSE(cJSON_HasObjectItem(item, NULL)); + TEST_ASSERT_FALSE(cJSON_IsInvalid(NULL)); + TEST_ASSERT_FALSE(cJSON_IsFalse(NULL)); + TEST_ASSERT_FALSE(cJSON_IsTrue(NULL)); + TEST_ASSERT_FALSE(cJSON_IsBool(NULL)); + TEST_ASSERT_FALSE(cJSON_IsNull(NULL)); + TEST_ASSERT_FALSE(cJSON_IsNumber(NULL)); + TEST_ASSERT_FALSE(cJSON_IsString(NULL)); + TEST_ASSERT_FALSE(cJSON_IsArray(NULL)); + TEST_ASSERT_FALSE(cJSON_IsObject(NULL)); + TEST_ASSERT_FALSE(cJSON_IsRaw(NULL)); + TEST_ASSERT_NULL(cJSON_CreateString(NULL)); + TEST_ASSERT_NULL(cJSON_CreateRaw(NULL)); + TEST_ASSERT_NULL(cJSON_CreateIntArray(NULL, 10)); + TEST_ASSERT_NULL(cJSON_CreateFloatArray(NULL, 10)); + TEST_ASSERT_NULL(cJSON_CreateDoubleArray(NULL, 10)); + TEST_ASSERT_NULL(cJSON_CreateStringArray(NULL, 10)); + cJSON_AddItemToArray(NULL, item); + cJSON_AddItemToArray(item, NULL); + cJSON_AddItemToObject(item, "item", NULL); + cJSON_AddItemToObject(item, NULL, item); + cJSON_AddItemToObject(NULL, "item", item); + cJSON_AddItemToObjectCS(item, "item", NULL); + cJSON_AddItemToObjectCS(item, NULL, item); + cJSON_AddItemToObjectCS(NULL, "item", item); + cJSON_AddItemReferenceToArray(NULL, item); + cJSON_AddItemReferenceToArray(item, NULL); + cJSON_AddItemReferenceToObject(item, "item", NULL); + cJSON_AddItemReferenceToObject(item, NULL, item); + cJSON_AddItemReferenceToObject(NULL, "item", item); + TEST_ASSERT_NULL(cJSON_DetachItemViaPointer(NULL, item)); + TEST_ASSERT_NULL(cJSON_DetachItemViaPointer(item, NULL)); + TEST_ASSERT_NULL(cJSON_DetachItemFromArray(NULL, 0)); + cJSON_DeleteItemFromArray(NULL, 0); + TEST_ASSERT_NULL(cJSON_DetachItemFromObject(NULL, "item")); + TEST_ASSERT_NULL(cJSON_DetachItemFromObject(item, NULL)); + TEST_ASSERT_NULL(cJSON_DetachItemFromObjectCaseSensitive(NULL, "item")); + TEST_ASSERT_NULL(cJSON_DetachItemFromObjectCaseSensitive(item, NULL)); + cJSON_DeleteItemFromObject(NULL, "item"); + cJSON_DeleteItemFromObject(item, NULL); + cJSON_DeleteItemFromObjectCaseSensitive(NULL, "item"); + cJSON_DeleteItemFromObjectCaseSensitive(item, NULL); + cJSON_InsertItemInArray(NULL, 0, item); + cJSON_InsertItemInArray(item, 0, NULL); + TEST_ASSERT_FALSE(cJSON_ReplaceItemViaPointer(NULL, item, item)); + TEST_ASSERT_FALSE(cJSON_ReplaceItemViaPointer(item, NULL, item)); + TEST_ASSERT_FALSE(cJSON_ReplaceItemViaPointer(item, item, NULL)); + cJSON_ReplaceItemInArray(item, 0, NULL); + cJSON_ReplaceItemInArray(NULL, 0, item); + cJSON_ReplaceItemInObject(NULL, "item", item); + cJSON_ReplaceItemInObject(item, NULL, item); + cJSON_ReplaceItemInObject(item, "item", NULL); + cJSON_ReplaceItemInObjectCaseSensitive(NULL, "item", item); + cJSON_ReplaceItemInObjectCaseSensitive(item, NULL, item); + cJSON_ReplaceItemInObjectCaseSensitive(item, "item", NULL); + TEST_ASSERT_NULL(cJSON_Duplicate(NULL, true)); + TEST_ASSERT_FALSE(cJSON_Compare(item, NULL, false)); + TEST_ASSERT_FALSE(cJSON_Compare(NULL, item, false)); + cJSON_Minify(NULL); + /* skipped because it is only used via a macro that checks for NULL */ + /* cJSON_SetNumberHelper(NULL, 0); */ + + cJSON_Delete(item); +} + int main(void) { UNITY_BEGIN(); @@ -338,6 +424,7 @@ int main(void) RUN_TEST(cjson_detach_item_via_pointer_should_detach_items); RUN_TEST(cjson_replace_item_via_pointer_should_replace_items); RUN_TEST(cjson_replace_item_in_object_should_preserve_name); + RUN_TEST(cjson_functions_shouldnt_crash_with_null_pointers); return UNITY_END(); } From 9bdf19fde1cc2e61c2f6820f891b9cdca772d10c Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 28 Jun 2017 15:58:22 +0200 Subject: [PATCH 026/307] handle null pointer: cJSONUtils_FindPointerFromObjectTo --- cJSON_Utils.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index c0fd649d..01cad631 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -162,6 +162,11 @@ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const obje size_t child_index = 0; cJSON *current_child = 0; + if ((object == NULL) || (target == NULL)) + { + return NULL; + } + if (object == target) { /* found */ From 1af74c8cc1cc59c7afbc441f3119378f3c7712d0 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 28 Jun 2017 15:58:58 +0200 Subject: [PATCH 027/307] handle null pointer: get_item_from_pointer --- cJSON_Utils.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 01cad631..bcdbb644 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -262,6 +262,12 @@ static cJSON_bool decode_array_index_from_pointer(const unsigned char * const po static cJSON *get_item_from_pointer(cJSON * const object, const char * pointer, const cJSON_bool case_sensitive) { cJSON *current_element = object; + + if (pointer == NULL) + { + return NULL; + } + /* follow path of the pointer */ while ((pointer[0] == '/') && (current_element != NULL)) { From c46c4d155967336776f697b4b0dd238ce89fed46 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 28 Jun 2017 15:59:53 +0200 Subject: [PATCH 028/307] handle null pointer: sort_object --- cJSON_Utils.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index bcdbb644..3e317ae1 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -550,6 +550,10 @@ static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive) static void sort_object(cJSON * const object, const cJSON_bool case_sensitive) { + if (object == NULL) + { + return; + } object->child = sort_list(object->child, case_sensitive); } From 2d252ae5957d5ddd43934822300c235ff154b4b6 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 28 Jun 2017 16:00:14 +0200 Subject: [PATCH 029/307] handle null pointer: compose_patch --- cJSON_Utils.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 3e317ae1..e13b9035 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1043,7 +1043,14 @@ CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, con static void compose_patch(cJSON * const patches, const unsigned char * const operation, const unsigned char * const path, const unsigned char *suffix, const cJSON * const value) { - cJSON *patch = cJSON_CreateObject(); + cJSON *patch = NULL; + + if ((patches == NULL) || (operation == NULL) || (path == NULL)) + { + return; + } + + patch = cJSON_CreateObject(); if (patch == NULL) { return; From f0c1b896bae0c7f83cdf49e11dc105cc808f1c16 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 28 Jun 2017 16:00:41 +0200 Subject: [PATCH 030/307] handle null pointers: cJSONUtils_GeneratePatches --- cJSON_Utils.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index e13b9035..35fc4500 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1228,7 +1228,14 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to) { - cJSON *patches = cJSON_CreateArray(); + cJSON *patches = NULL; + + if ((from == NULL) || (to == NULL)) + { + return NULL; + } + + patches = cJSON_CreateArray(); create_patches(patches, (const unsigned char*)"", from, to, false); return patches; From 93227319f04bb248eede012e804d0fcaf80d6dfb Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 28 Jun 2017 16:00:59 +0200 Subject: [PATCH 031/307] handle null pointers: cJSONUtils_GeneratePatchesCaseSensitive --- cJSON_Utils.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 35fc4500..84319cc5 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1243,7 +1243,14 @@ CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * con CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to) { - cJSON *patches = cJSON_CreateArray(); + cJSON *patches = NULL; + + if ((from == NULL) || (to == NULL)) + { + return NULL; + } + + patches = cJSON_CreateArray(); create_patches(patches, (const unsigned char*)"", from, to, true); return patches; From 18ad8a8770d42f3fdb3ac630527ba36a0258be59 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 28 Jun 2017 16:01:20 +0200 Subject: [PATCH 032/307] misc_utils_tests: call all utils function with NULL pointers --- tests/CMakeLists.txt | 3 +- tests/misc_utils_tests.c | 80 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/misc_utils_tests.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5dee1af7..47d7c1a1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -84,7 +84,8 @@ if(ENABLE_CJSON_TEST) set (cjson_utils_tests json_patch_tests - old_utils_tests) + old_utils_tests + misc_utils_tests) foreach (cjson_utils_test ${cjson_utils_tests}) add_executable("${cjson_utils_test}" "${cjson_utils_test}.c") diff --git a/tests/misc_utils_tests.c b/tests/misc_utils_tests.c new file mode 100644 index 00000000..7d300bc8 --- /dev/null +++ b/tests/misc_utils_tests.c @@ -0,0 +1,80 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include +#include + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" +#include "../cJSON_Utils.h" + +static void cjson_utils_functions_shouldnt_crash_with_null_pointers(void) +{ + cJSON *item = cJSON_CreateString("item"); + TEST_ASSERT_NOT_NULL(item); + + TEST_ASSERT_NULL(cJSONUtils_GetPointer(item, NULL)); + TEST_ASSERT_NULL(cJSONUtils_GetPointer(NULL, "pointer")); + TEST_ASSERT_NULL(cJSONUtils_GetPointerCaseSensitive(NULL, "pointer")); + TEST_ASSERT_NULL(cJSONUtils_GetPointerCaseSensitive(item, NULL)); + TEST_ASSERT_NULL(cJSONUtils_GeneratePatches(item, NULL)); + TEST_ASSERT_NULL(cJSONUtils_GeneratePatches(NULL, item)); + TEST_ASSERT_NULL(cJSONUtils_GeneratePatchesCaseSensitive(item, NULL)); + TEST_ASSERT_NULL(cJSONUtils_GeneratePatchesCaseSensitive(NULL, item)); + cJSONUtils_AddPatchToArray(item, "path", "add", NULL); + cJSONUtils_AddPatchToArray(item, "path", NULL, item); + cJSONUtils_AddPatchToArray(item, NULL, "add", item); + cJSONUtils_AddPatchToArray(NULL, "path", "add", item); + cJSONUtils_ApplyPatches(item, NULL); + cJSONUtils_ApplyPatches(NULL, item); + cJSONUtils_ApplyPatchesCaseSensitive(item, NULL); + cJSONUtils_ApplyPatchesCaseSensitive(NULL, item); + TEST_ASSERT_NULL(cJSONUtils_MergePatch(item, NULL)); + item = cJSON_CreateString("item"); + TEST_ASSERT_NULL(cJSONUtils_MergePatchCaseSensitive(item, NULL)); + item = cJSON_CreateString("item"); + /* these calls are actually valid */ + /* cJSONUtils_MergePatch(NULL, item); */ + /* cJSONUtils_MergePatchCaseSensitive(NULL, item);*/ + /* cJSONUtils_GenerateMergePatch(item, NULL); */ + /* cJSONUtils_GenerateMergePatch(NULL, item); */ + /* cJSONUtils_GenerateMergePatchCaseSensitive(item, NULL); */ + /* cJSONUtils_GenerateMergePatchCaseSensitive(NULL, item); */ + + TEST_ASSERT_NULL(cJSONUtils_FindPointerFromObjectTo(item, NULL)); + TEST_ASSERT_NULL(cJSONUtils_FindPointerFromObjectTo(NULL, item)); + cJSONUtils_SortObject(NULL); + cJSONUtils_SortObjectCaseSensitive(NULL); + + cJSON_Delete(item); +} + +int main(void) +{ + UNITY_BEGIN(); + + RUN_TEST(cjson_utils_functions_shouldnt_crash_with_null_pointers); + + return UNITY_END(); +} From d3bc571a38bb1bea06cc8b263b66a41a84bb7322 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 28 Jun 2017 16:31:11 +0200 Subject: [PATCH 033/307] Release Version 1.5.6 --- CHANGELOG.md | 6 ++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c4e6031..d21eba43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +1.5.6 +===== +Fixes: +------ +* Make cJSON a lot more tolerant about passing NULL pointers to its functions, it should now fail safely instead of dereferencing the pointer. (#183) Thanks @msichal for reporting #182 + 1.5.5 ===== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 2da43a95..a3f6f6b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project(cJSON C) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 5) -set(PROJECT_VERSION_PATCH 5) +set(PROJECT_VERSION_PATCH 6) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 16e7eb75..dca5e6ce 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.5.5 +LIBVERSION = 1.5.6 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index fdc136f3..314560b7 100644 --- a/cJSON.c +++ b/cJSON.c @@ -58,7 +58,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 5) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 6) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 71d8dbb1..ef6e7651 100644 --- a/cJSON.h +++ b/cJSON.h @@ -31,7 +31,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 5 -#define CJSON_VERSION_PATCH 5 +#define CJSON_VERSION_PATCH 6 #include From 38b2f40a9abc6e73d33b9cb0440900b8c3e46d6f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 10 May 2017 01:17:36 +0200 Subject: [PATCH 034/307] Add warning -Wunused-macro --- CMakeLists.txt | 1 + cJSON.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a3f6f6b0..8944894b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) -Wdouble-promotion -Wparentheses -Wformat-overflow + -Wunused-macros ) endif() diff --git a/cJSON.c b/cJSON.c index 314560b7..6e8255a3 100644 --- a/cJSON.c +++ b/cJSON.c @@ -208,7 +208,6 @@ typedef struct /* check if the given size is left to read in a given parse buffer (starting with 1) */ #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) -#define cannot_read(buffer, size) (!can_read(buffer, size)) /* check if the buffer can be accessed at the given index (starting with 0) */ #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) From 4e0c119391ae952dd1ba02c8c3a7279ef31d6329 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 10 May 2017 01:19:52 +0200 Subject: [PATCH 035/307] Add warning -Wmissing-variable-declarations --- CMakeLists.txt | 1 + tests/json_patch_tests.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8944894b..7dbb289f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) -Wparentheses -Wformat-overflow -Wunused-macros + -Wmissing-variable-declarations ) endif() diff --git a/tests/json_patch_tests.c b/tests/json_patch_tests.c index 3d4df418..c2c88a4f 100644 --- a/tests/json_patch_tests.c +++ b/tests/json_patch_tests.c @@ -119,7 +119,7 @@ static cJSON_bool test_apply_patch(const cJSON * const test) return successful; } -static cJSON_bool test_generate_test(cJSON *test __attribute__((unused))) +static cJSON_bool test_generate_test(cJSON *test) { cJSON *doc = NULL; cJSON *patch = NULL; From eb8c0baa3b3e35ce83cc063041935c07ec778fff Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 10 May 2017 01:20:58 +0200 Subject: [PATCH 036/307] Add warning -Wused-but-marked-unused --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7dbb289f..1c3f69ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) -Wformat-overflow -Wunused-macros -Wmissing-variable-declarations + -Wused-but-marked-unused ) endif() From a9ce4e6bbc44048ae8f8786008d6ee9b316c65fb Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 10 May 2017 01:21:13 +0200 Subject: [PATCH 037/307] Add warning -Wswitch-enum --- CMakeLists.txt | 1 + tests/CMakeLists.txt | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c3f69ee..151eb290 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) -Wunused-macros -Wmissing-variable-declarations -Wused-but-marked-unused + -Wswitch-enum ) endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 47d7c1a1..d69f3f82 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,6 +25,14 @@ if(ENABLE_CJSON_TEST) target_compile_options(unity PRIVATE "-fno-sanitize=float-divide-by-zero") endif() endif() + # Disable -Wswitch-enum for Unity + if (FLAG_SUPPORTED_Wswitchenum) + if ("${CMAKE_VERSION}" VERSION_LESS "2.8.12") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-switch-enum") + else() + target_compile_options(unity PRIVATE "-Wno-switch-enum") + endif() + endif() #copy test files file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/inputs") From 21733eb02e8458181a5f2d06acb4a5cfc6e71b3f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 14 May 2017 14:49:27 +0200 Subject: [PATCH 038/307] tests/print_number: Use proper double literals --- tests/print_number.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/print_number.c b/tests/print_number.c index 299cefc3..bda455c5 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -49,16 +49,16 @@ static void print_number_should_print_zero(void) static void print_number_should_print_negative_integers(void) { - assert_print_number("-1", -1); - assert_print_number("-32768", -32768); + assert_print_number("-1", -1.0); + assert_print_number("-32768", -32768.0); assert_print_number("-2147483648", -2147483648.0); } static void print_number_should_print_positive_integers(void) { - assert_print_number("1", 1); - assert_print_number("32767", 32767); - assert_print_number("2147483647", 2147483647); + assert_print_number("1", 1.0); + assert_print_number("32767", 32767.0); + assert_print_number("2147483647", 2147483647.0); } static void print_number_should_print_positive_reals(void) From e872d402235f1e5aecb99a32960fc0bbb478b9c9 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 17 Jun 2017 14:21:08 +0200 Subject: [PATCH 039/307] MSVC: Disable deprecation warnings for C89 functions C89 sadly doesn't provide safe alternatives for strcpy, sprintf and the like. --- cJSON.c | 5 +++++ cJSON_Utils.c | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/cJSON.c b/cJSON.c index 6e8255a3..9c86128b 100644 --- a/cJSON.c +++ b/cJSON.c @@ -23,6 +23,11 @@ /* cJSON */ /* JSON parser in C. */ +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif + #ifdef __GNUC__ #pragma GCC visibility push(default) #endif diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 84319cc5..e7bf802b 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -20,6 +20,10 @@ THE SOFTWARE. */ +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif #pragma GCC visibility push(default) #include #include From 217ab0261248a0b698f8201987169266f71a8373 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 17 Jun 2017 14:23:12 +0200 Subject: [PATCH 040/307] cJSON_Utils: Guard gcc pragmas with a check for __GCC__ --- cJSON_Utils.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index e7bf802b..2baa492c 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -24,13 +24,18 @@ #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) #define _CRT_SECURE_NO_DEPRECATE #endif + +#ifdef __GNUCC__ #pragma GCC visibility push(default) +#endif #include #include #include #include #include +#ifdef __GNUCC__ #pragma GCC visibility pop +#endif #include "cJSON_Utils.h" From 45e1278acbf789b1a855b2cc81112b4768a27b3b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 14 May 2017 14:49:55 +0200 Subject: [PATCH 041/307] tests/print_number: Add test with 17 digits of precision --- tests/print_number.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/print_number.c b/tests/print_number.c index bda455c5..5ebb3489 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -68,6 +68,7 @@ static void print_number_should_print_positive_reals(void) assert_print_number("1000000000000", 10e11); assert_print_number("1.23e+129", 123e+127); assert_print_number("1.23e-126", 123e-128); + assert_print_number("3.1415926535897931", 3.1415926535897931); } static void print_number_should_print_negative_reals(void) From 0d675cb048b9fd4ad5365e6df336b33ae3374275 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 17 Jun 2017 14:26:25 +0200 Subject: [PATCH 042/307] MSVC: Disable warning about single line comments in system headers --- cJSON.c | 8 ++++++++ cJSON_Utils.c | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/cJSON.c b/cJSON.c index 9c86128b..e816cdef 100644 --- a/cJSON.c +++ b/cJSON.c @@ -31,6 +31,11 @@ #ifdef __GNUC__ #pragma GCC visibility push(default) #endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif #include #include @@ -41,6 +46,9 @@ #include #include +#if defined(_MSC_VER) +#pragma warning (pop) +#endif #ifdef __GNUC__ #pragma GCC visibility pop #endif diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 2baa492c..b83cfcd4 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -28,11 +28,21 @@ #ifdef __GNUCC__ #pragma GCC visibility push(default) #endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif + #include #include #include #include #include + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif #ifdef __GNUCC__ #pragma GCC visibility pop #endif From 04e27dc8c51afce0fe9fccc628eeb29661c6684a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 7 Jun 2017 00:15:23 +0200 Subject: [PATCH 043/307] CMake: New option BUILD_SHARED_AND_STATIC_LIBS --- CMakeLists.txt | 31 ++++++++++++++++++++++++++++--- README.md | 1 + 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 151eb290..f012f95b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,7 +103,17 @@ set(CJSON_LIB cjson) file(GLOB HEADERS cJSON.h) set(SOURCES cJSON.c) -add_library("${CJSON_LIB}" "${HEADERS}" "${SOURCES}") +option(BUILD_SHARED_AND_STATIC_LIBS "Build both shared and static libraries" Off) + +if (NOT BUILD_SHARED_AND_STATIC_LIBS) + add_library("${CJSON_LIB}" "${HEADERS}" "${SOURCES}") +else() + # See https://cmake.org/Wiki/CMake_FAQ#How_do_I_make_my_shared_and_static_libraries_have_the_same_root_name.2C_but_different_suffixes.3F + add_library("${CJSON_LIB}" SHARED "${HEADERS}" "${SOURCES}") + add_library("${CJSON_LIB}-static" STATIC "${HEADERS}" "${SOURCES}") + set_target_properties("${CJSON_LIB}-static" PROPERTIES OUTPUT_NAME "${CJSON_LIB}") + set_target_properties("${CJSON_LIB}-static" PROPERTIES PREFIX "lib") +endif() if (NOT WIN32) target_link_libraries("${CJSON_LIB}" m) endif() @@ -114,6 +124,9 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson.pc.in" install(FILES cJSON.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cjson") install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") install(TARGETS "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" EXPORT "${CJSON_LIB}") +if (BUILD_SHARED_AND_STATIC_LIBS) + install(TARGETS "${CJSON_LIB}-static" DESTINATION "${CMAKE_INSTALL_LIBDIR}") +endif() if(ENABLE_TARGET_EXPORT) # export library information for CMake projects install(EXPORT "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON") @@ -132,13 +145,25 @@ if(ENABLE_CJSON_UTILS) file(GLOB HEADERS_UTILS cJSON_Utils.h) set(SOURCES_UTILS cJSON_Utils.c) - add_library("${CJSON_UTILS_LIB}" "${HEADERS_UTILS}" "${SOURCES_UTILS}") - target_link_libraries("${CJSON_UTILS_LIB}" "${CJSON_LIB}") + if (NOT BUILD_SHARED_AND_STATIC_LIBS) + add_library("${CJSON_UTILS_LIB}" "${HEADERS_UTILS}" "${SOURCES_UTILS}") + target_link_libraries("${CJSON_UTILS_LIB}" "${CJSON_LIB}") + else() + add_library("${CJSON_UTILS_LIB}" SHARED "${HEADERS_UTILS}" "${SOURCES_UTILS}") + target_link_libraries("${CJSON_UTILS_LIB}" "${CJSON_LIB}") + add_library("${CJSON_UTILS_LIB}-static" STATIC "${HEADERS_UTILS}" "${SOURCES_UTILS}") + target_link_libraries("${CJSON_UTILS_LIB}-static" "${CJSON_LIB}-static") + set_target_properties("${CJSON_UTILS_LIB}-static" PROPERTIES OUTPUT_NAME "${CJSON_UTILS_LIB}") + set_target_properties("${CJSON_UTILS_LIB}-static" PROPERTIES PREFIX "lib") + endif() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson_utils.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" @ONLY) install(TARGETS "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" EXPORT "${CJSON_UTILS_LIB}") + if (BUILD_SHARED_AND_STATIC_LIBS) + install(TARGETS "${CJSON_UTILS_LIB}-static" DESTINATION "${CMAKE_INSTALL_LIBDIR}") + endif() install(FILES cJSON_Utils.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cjson") install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") if(ENABLE_TARGET_EXPORT) diff --git a/README.md b/README.md index 4dba514a..b22025a6 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,7 @@ You can change the build process with a list of different options that you can p * `-DENABLE_VALGRIND=On`: Run tests with [valgrind](http://valgrind.org). (off by default) * `-DENABLE_SANITIZERS=On`: Compile cJSON with [AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) and [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) enabled (if possible). (off by default) * `-DBUILD_SHARED_LIBS=On`: Build the shared libraries. (on by default) +* `-DBUILD_SHARED_AND_STATIC_LIBS=On`: Build both shared and static libraries. (off by default) * `-DCMAKE_INSTALL_PREFIX=/usr`: Set a prefix for the installation. If you are packaging cJSON for a distribution of Linux, you would probably take these steps for example: From d1c2e2df4a7cddaae621d2d9c973fa8b8f6b672d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 17 Jun 2017 14:33:04 +0200 Subject: [PATCH 044/307] MSVC: workaround for C2322 --- cJSON.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index e816cdef..f6ee1ad3 100644 --- a/cJSON.c +++ b/cJSON.c @@ -114,7 +114,27 @@ typedef struct internal_hooks void *(*reallocate)(void *pointer, size_t size); } internal_hooks; -static internal_hooks global_hooks = { malloc, free, realloc }; +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dillimport '...' is not static */ +static void *internal_malloc(size_t size) +{ + return malloc(size); +} +static void internal_free(void *pointer) +{ + free(pointer); +} +static void *internal_realloc(void *pointer, size_t size) +{ + return realloc(pointer, size); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) { From ac368e9dfb3bc5ab23e2495fbb8234f090424b8b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 17 Jun 2017 14:33:55 +0200 Subject: [PATCH 045/307] MSVC: Fix warning about assignment in condition --- cJSON.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index f6ee1ad3..81b91972 100644 --- a/cJSON.c +++ b/cJSON.c @@ -147,7 +147,8 @@ static unsigned char* cJSON_strdup(const unsigned char* string, const internal_h } length = strlen((const char*)string) + sizeof(""); - if (!(copy = (unsigned char*)hooks->allocate(length))) + copy = (unsigned char*)hooks->allocate(length); + if (copy == NULL) { return NULL; } From e174831819e46afc5797974efd92c92cb13bc9bd Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 17 Jun 2017 14:42:52 +0200 Subject: [PATCH 046/307] CMake: Add custom compiler flags for MSVC --- CMakeLists.txt | 67 ++++++++++++++++++++++++++++---------------------- README.md | 2 +- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f012f95b..a55acacb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,37 +16,46 @@ set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT set(custom_compiler_flags) include(CheckCCompilerFlag) -option(ENABLE_CUSTOM_COMPILER_FLAGS "Enables custom compiler flags for Clang and GCC" ON) +option(ENABLE_CUSTOM_COMPILER_FLAGS "Enables custom compiler flags" ON) if (ENABLE_CUSTOM_COMPILER_FLAGS) - list(APPEND custom_compiler_flags - -std=c89 - -pedantic - -Wall - -Wextra - -Werror - -Wstrict-prototypes - -Wwrite-strings - -Wshadow - -Winit-self - -Wcast-align - -Wformat=2 - -Wmissing-prototypes - -Wstrict-overflow=2 - -Wcast-qual - -Wundef - -Wswitch-default - -Wconversion - -Wc++-compat - -fstack-protector-strong - -Wcomma - -Wdouble-promotion - -Wparentheses - -Wformat-overflow - -Wunused-macros - -Wmissing-variable-declarations - -Wused-but-marked-unused - -Wswitch-enum + if (("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") OR ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")) + list(APPEND custom_compiler_flags + -std=c89 + -pedantic + -Wall + -Wextra + -Werror + -Wstrict-prototypes + -Wwrite-strings + -Wshadow + -Winit-self + -Wcast-align + -Wformat=2 + -Wmissing-prototypes + -Wstrict-overflow=2 + -Wcast-qual + -Wundef + -Wswitch-default + -Wconversion + -Wc++-compat + -fstack-protector-strong + -Wcomma + -Wdouble-promotion + -Wparentheses + -Wformat-overflow + -Wunused-macros + -Wmissing-variable-declarations + -Wused-but-marked-unused + -Wswitch-enum + ) + elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + list(APPEND custom_compiler_flags + /GS + /Za + /sdl + /W4 ) + endif() endif() option(ENABLE_SANITIZERS "Enables AddressSanitizer and UndefinedBehaviorSanitizer." OFF) diff --git a/README.md b/README.md index b22025a6..a363f52e 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ You can change the build process with a list of different options that you can p * `-DENABLE_CJSON_TEST=On`: Enable building the tests. (on by default) * `-DENABLE_CJSON_UTILS=On`: Enable building cJSON_Utils. (off by default) * `-DENABLE_TARGET_EXPORT=On`: Enable the export of CMake targets. Turn off if it makes problems. (on by default) -* `-DENABLE_CUSTOM_COMPILER_FLAGS=On`: Enable custom compiler flags (currently for Clang and GCC). Turn off if it makes problems. (on by default) +* `-DENABLE_CUSTOM_COMPILER_FLAGS=On`: Enable custom compiler flags (currently for Clang, GCC and MSVC). Turn off if it makes problems. (on by default) * `-DENABLE_VALGRIND=On`: Run tests with [valgrind](http://valgrind.org). (off by default) * `-DENABLE_SANITIZERS=On`: Compile cJSON with [AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) and [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) enabled (if possible). (off by default) * `-DBUILD_SHARED_LIBS=On`: Build the shared libraries. (on by default) From 7a2615c2315713ca1a96d37e8a2015b371e6258d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 17 Jun 2017 15:04:29 +0200 Subject: [PATCH 047/307] Fix: Check if __GNUCC__ is defined This has been detected via MSVC's Warning C4668 --- cJSON.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index 81b91972..b689361b 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1849,7 +1849,7 @@ CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSO item->type &= ~cJSON_StringIsConst; } -#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) #pragma GCC diagnostic push #endif #ifdef __GNUC__ @@ -1871,7 +1871,7 @@ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJ item->type |= cJSON_StringIsConst; cJSON_AddItemToArray(object, item); } -#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) #pragma GCC diagnostic pop #endif From 5baa77f86cb9dffe20b5f9ab85e00baa8fe70a0b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 3 Jul 2017 21:43:14 +0200 Subject: [PATCH 048/307] cJSON_Parse{,WithOpts}: Skip UTF-8 (Byte Order Marks) --- cJSON.c | 19 +++++++++++++++++-- tests/misc_tests.c | 26 ++++++++++++++++++++++++++ tests/parse_with_opts.c | 17 +++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index b689361b..9c567ff9 100644 --- a/cJSON.c +++ b/cJSON.c @@ -958,6 +958,22 @@ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) return buffer; } +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + /* Parse an object - create a new root, and populate. */ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) { @@ -984,7 +1000,7 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return goto fail; } - if (!parse_value(item, buffer_skip_whitespace(&buffer))) + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) { /* parse failure. ep is set. */ goto fail; @@ -1222,7 +1238,6 @@ static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buf return parse_object(item, input_buffer); } - return false; } diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 7d511793..2f1efe4e 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -410,6 +410,30 @@ static void cjson_functions_shouldnt_crash_with_null_pointers(void) cJSON_Delete(item); } +static void skip_utf8_bom_should_skip_bom(void) +{ + const unsigned char string[] = "\xEF\xBB\xBF{}"; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + buffer.content = string; + buffer.length = sizeof(string); + buffer.hooks = global_hooks; + + TEST_ASSERT_TRUE(skip_utf8_bom(&buffer) == &buffer); + TEST_ASSERT_EQUAL_UINT(3U, (unsigned int)buffer.offset); +} + +static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void) +{ + const unsigned char string[] = " \xEF\xBB\xBF{}"; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + buffer.content = string; + buffer.length = sizeof(string); + buffer.hooks = global_hooks; + buffer.offset = 1; + + TEST_ASSERT_NULL(skip_utf8_bom(&buffer)); +} + int main(void) { UNITY_BEGIN(); @@ -425,6 +449,8 @@ int main(void) RUN_TEST(cjson_replace_item_via_pointer_should_replace_items); RUN_TEST(cjson_replace_item_in_object_should_preserve_name); RUN_TEST(cjson_functions_shouldnt_crash_with_null_pointers); + RUN_TEST(skip_utf8_bom_should_skip_bom); + RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); return UNITY_END(); } diff --git a/tests/parse_with_opts.c b/tests/parse_with_opts.c index 05574676..066d2cd6 100644 --- a/tests/parse_with_opts.c +++ b/tests/parse_with_opts.c @@ -69,6 +69,22 @@ static void parse_with_opts_should_return_parse_end(void) cJSON_Delete(item); } +static void parse_with_opts_should_parse_utf8_bom(void) +{ + cJSON *with_bom = NULL; + cJSON *without_bom = NULL; + + with_bom = cJSON_ParseWithOpts("\xEF\xBB\xBF{}", NULL, true); + TEST_ASSERT_NOT_NULL(with_bom); + without_bom = cJSON_ParseWithOpts("{}", NULL, true); + TEST_ASSERT_NOT_NULL(with_bom); + + TEST_ASSERT_TRUE(cJSON_Compare(with_bom, without_bom, true)); + + cJSON_Delete(with_bom); + cJSON_Delete(without_bom); +} + int main(void) { UNITY_BEGIN(); @@ -77,6 +93,7 @@ int main(void) RUN_TEST(parse_with_opts_should_handle_empty_strings); RUN_TEST(parse_with_opts_should_require_null_if_requested); RUN_TEST(parse_with_opts_should_return_parse_end); + RUN_TEST(parse_with_opts_should_parse_utf8_bom); return UNITY_END(); } From bf0bc22a1186a3dad2e1d7d1abdf64b64291b512 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 5 Jul 2017 10:31:00 +0200 Subject: [PATCH 049/307] CMake: Add ENABLE_SAFE_STACK option --- .travis.yml | 2 +- CMakeLists.txt | 10 ++++++++++ README.md | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d722664a..e7ff744e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,6 @@ addons: script: - mkdir build - cd build - - cmake .. -DENABLE_CJSON_UTILS=On -DENABLE_VALGRIND="${VALGRIND}" -DENABLE_SANITIZERS="${SANITIZERS}" + - cmake .. -DENABLE_CJSON_UTILS=On -DENABLE_VALGRIND="${VALGRIND}" -DENABLE_SAFE_STACK="${VALGRIND}" -DENABLE_SANITIZERS="${SANITIZERS}" - make - make test CTEST_OUTPUT_ON_FAILURE=On diff --git a/CMakeLists.txt b/CMakeLists.txt index a55acacb..ec5196b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,16 @@ if (ENABLE_SANITIZERS) ) endif() +option(ENABLE_SAFE_STACK "Enables the SafeStack instrumentation pass by the Code Pointer Integrity Project" OFF) +if (ENABLE_SAFE_STACK) + if (ENABLE_SANITIZERS) + message(FATAL_ERROR "ENABLE_SAFE_STACK cannot be used in combination with ENABLE_SANITIZERS") + endif() + list(APPEND custom_compiler_flags + -fsanitize=safe-stack + ) +endif() + option(ENABLE_PUBLIC_SYMBOLS "Export library symbols." On) if (ENABLE_PUBLIC_SYMBOLS) list(APPEND custom_compiler_flags -fvisibility=hidden) diff --git a/README.md b/README.md index a363f52e..6ff4e954 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ You can change the build process with a list of different options that you can p * `-DENABLE_CUSTOM_COMPILER_FLAGS=On`: Enable custom compiler flags (currently for Clang, GCC and MSVC). Turn off if it makes problems. (on by default) * `-DENABLE_VALGRIND=On`: Run tests with [valgrind](http://valgrind.org). (off by default) * `-DENABLE_SANITIZERS=On`: Compile cJSON with [AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) and [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) enabled (if possible). (off by default) +* `-DENABLE_SAFE_STACK`: Enable the [SafeStack](https://clang.llvm.org/docs/SafeStack.html) instrumentation pass. Currently only works with the Clang compiler. (off by default) * `-DBUILD_SHARED_LIBS=On`: Build the shared libraries. (on by default) * `-DBUILD_SHARED_AND_STATIC_LIBS=On`: Build both shared and static libraries. (off by default) * `-DCMAKE_INSTALL_PREFIX=/usr`: Set a prefix for the installation. From a3c2eba991af2aabe3b5454d35fad226f5941087 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Sat, 8 Jul 2017 09:39:06 +0200 Subject: [PATCH 050/307] Fix typos in json.dict --- fuzzing/json.dict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fuzzing/json.dict b/fuzzing/json.dict index ac9c08c8..9bb03d7f 100644 --- a/fuzzing/json.dict +++ b/fuzzing/json.dict @@ -25,8 +25,8 @@ escape_sequence_r="\\r" escape_sequence_t="\\t" escape_sequence_quote="\\\"" escape_sequence_backslash="\\\\" -escapce_sequence_slash="\\/" -escpae_sequence_utf16_base="\\u" +escape_sequence_slash="\\/" +escape_sequence_utf16_base="\\u" escape_sequence_utf16="\\u12ab" number_integer="1" From dd980008f712ce5b46b95afc6068a0b2121581e5 Mon Sep 17 00:00:00 2001 From: simon-p-r Date: Sun, 9 Jul 2017 22:20:35 +0100 Subject: [PATCH 051/307] add appveyor --- appveyor.yml | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..db5f2a43 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,82 @@ +os: Visual Studio 2015 + +# ENABLE_CUSTOM_COMPILER_FLAGS - on by default +# ENABLE_SANITIZERS - off by default +# ENABLE_PUBLIC_SYMBOLS - on by default +# BUILD_SHARED_LIBS - on by default +# ENABLE_TARGET_EXPORT - on by default +# ENABLE_CJSON_UTILS - off by default +# ENABLE_CJSON_TEST -on by default +# ENABLE_VALGRIND - off by default +# ENABLE_FUZZING - off by default + +environment: + matrix: + - GENERATOR: "Visual Studio 14 2015" + BUILD_SHARED_LIBS: ON + ENABLE_CJSON_TEST: OFF + ENABLE_CJSON_UTILS: ON + + - GENERATOR: "Visual Studio 14 2015" + BUILD_SHARED_LIBS: OFF + ENABLE_CJSON_TEST: OFF + ENABLE_CJSON_UTILS: ON + + - GENERATOR: "Visual Studio 12 2013" + BUILD_SHARED_LIBS: ON + ENABLE_CJSON_TEST: OFF + ENABLE_CJSON_UTILS: ON + + - GENERATOR: "Visual Studio 12 2013" + BUILD_SHARED_LIBS: OFF + ENABLE_CJSON_TEST: OFF + ENABLE_CJSON_UTILS: ON + + - GENERATOR: "Visual Studio 11 2012" + BUILD_SHARED_LIBS: ON + ENABLE_CJSON_TEST: OFF + ENABLE_CJSON_UTILS: ON + + - GENERATOR: "Visual Studio 11 2012" + BUILD_SHARED_LIBS: OFF + ENABLE_CJSON_TEST: OFF + ENABLE_CJSON_UTILS: ON + + - GENERATOR: "Visual Studio 10 2010" + BUILD_SHARED_LIBS: ON + ENABLE_CJSON_TEST: OFF + ENABLE_CJSON_UTILS: ON + + - GENERATOR: "Visual Studio 10 2010" + BUILD_SHARED_LIBS: OFF + ENABLE_CJSON_TEST: OFF + ENABLE_CJSON_UTILS: ON + + - GENERATOR: "Visual Studio 9 2008" + BUILD_SHARED_LIBS: ON + ENABLE_CJSON_TEST: OFF + ENABLE_CJSON_UTILS: ON + + - GENERATOR: "Visual Studio 9 2008" + BUILD_SHARED_LIBS: OFF + ENABLE_CJSON_TEST: OFF + ENABLE_CJSON_UTILS: ON + + +platform: + - x86 + - x64 + +configuration: + - Release + + +build_script: + - ps: if($env:PLATFORM -eq "x64") { $env:CMAKE_GEN_SUFFIX=" Win64" } + - cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% -DENABLE_CJSON_TEST=%ENABLE_CJSON_TEST% -H. -Bbuild + - cmake --build build --config "%CONFIGURATION%" + + +on_failure: + - ps: if(Test-Path builds/CMakeFiles/CMakeOutput.log) { cat builds/CMakeFiles/CMakeOutput.log } + - ps: if(Test-Path builds/CMakeFiles/CMakeError.log) { cat builds/CMakeFiles/CMakeError.log } \ No newline at end of file From 824e1b2a99793341f97195209896169b8b33b0a7 Mon Sep 17 00:00:00 2001 From: simon-p-r Date: Mon, 10 Jul 2017 10:38:21 +0100 Subject: [PATCH 052/307] patch for Visual Studio 9 2008 x64 failed builds --- appveyor-patch.ps1 | 11 +++++++++++ appveyor.yml | 1 + 2 files changed, 12 insertions(+) create mode 100644 appveyor-patch.ps1 diff --git a/appveyor-patch.ps1 b/appveyor-patch.ps1 new file mode 100644 index 00000000..34d2163a --- /dev/null +++ b/appveyor-patch.ps1 @@ -0,0 +1,11 @@ +# Script to patch Appveyor build environment for Visual Studio 2008 64bit + +$url = "https://github.com/menpo/condaci/raw/master/vs2008_patch.zip" +$output = "$pwd\build\vs2008_patch.zip" + +(New-Object System.Net.WebClient).DownloadFile($url, $output) + +7z -e "$pwd\build\vs2008_patch.zip" +cmd.exe /c "$pwd\build\vs2008_patch\setup_x64.bat" + + diff --git a/appveyor.yml b/appveyor.yml index db5f2a43..f9c586af 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -72,6 +72,7 @@ configuration: build_script: + - ps: if($env:PLATFORM -eq "x64" -And $GENERATOR -eq 'Visual Studio 9 2008') { .\appveyor-patch.ps1 } - ps: if($env:PLATFORM -eq "x64") { $env:CMAKE_GEN_SUFFIX=" Win64" } - cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% -DENABLE_CJSON_TEST=%ENABLE_CJSON_TEST% -H. -Bbuild - cmake --build build --config "%CONFIGURATION%" From c6f7f78cbbf8d549d833bd5f261e74303829cb7f Mon Sep 17 00:00:00 2001 From: simon-p-r Date: Mon, 10 Jul 2017 10:50:55 +0100 Subject: [PATCH 053/307] added copy to powershell script --- appveyor-patch.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor-patch.ps1 b/appveyor-patch.ps1 index 34d2163a..b380d53b 100644 --- a/appveyor-patch.ps1 +++ b/appveyor-patch.ps1 @@ -8,4 +8,6 @@ $output = "$pwd\build\vs2008_patch.zip" 7z -e "$pwd\build\vs2008_patch.zip" cmd.exe /c "$pwd\build\vs2008_patch\setup_x64.bat" +copy C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\amd64\vcvarsamd64.bat + From 954d61e5e7cb9dc6c480fc28ac1cdceca07dd5bd Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 12 Jul 2017 22:58:06 +0200 Subject: [PATCH 054/307] Fix #189, ensure returns an invalid pointer If realloc returns NULL, ensure didn't abort but returned printbuffer.offset instead. If an attacker can control printbuffer.offset and also make realloc fail at just the right moment, this would make cJSON potentially write at an arbitrary memory address. --- cJSON.c | 8 ++++++++ tests/misc_tests.c | 18 +++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 314560b7..753b2156 100644 --- a/cJSON.c +++ b/cJSON.c @@ -377,6 +377,14 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) { /* reallocate with realloc if available */ newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } } else { diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 7d511793..03a6e736 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -410,6 +410,22 @@ static void cjson_functions_shouldnt_crash_with_null_pointers(void) cJSON_Delete(item); } +static void *failing_realloc(void *pointer, size_t size) +{ + (void)size; + (void)pointer; + return NULL; +} + +static void ensure_should_fail_on_failed_realloc(void) +{ + printbuffer buffer = {NULL, 10, 0, 0, false, false, {&malloc, &free, &failing_realloc}}; + buffer.buffer = (unsigned char*)malloc(100); + TEST_ASSERT_NOT_NULL(buffer.buffer); + + TEST_ASSERT_NULL_MESSAGE(ensure(&buffer, 200), "Ensure didn't fail with failing realloc."); +} + int main(void) { UNITY_BEGIN(); @@ -425,6 +441,6 @@ int main(void) RUN_TEST(cjson_replace_item_via_pointer_should_replace_items); RUN_TEST(cjson_replace_item_in_object_should_preserve_name); RUN_TEST(cjson_functions_shouldnt_crash_with_null_pointers); - + RUN_TEST(ensure_should_fail_on_failed_realloc); return UNITY_END(); } From 88d66c5da9431d97108da4711b44f6adf70f9e49 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 12 Jul 2017 23:13:14 +0200 Subject: [PATCH 055/307] Release version 1.5.7 --- CHANGELOG.md | 7 +++++++ CMakeLists.txt | 2 +- CONTRIBUTORS.md | 1 + Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 6 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d21eba43..a017d871 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +1.5.7 +===== +Fixes: +------ +* Fix a bug where realloc failing would return a pointer to an invalid memory address. This is a security issue as it could potentially be used by an attacker to write to arbitrary memory addresses. (see #189), fixed in (954d61e5e7cb9dc6c480fc28ac1cdceca07dd5bd), big thanks @timothyjohncarney for reporting this issue +* Fix a spelling mistake in the AFL fuzzer dictionary (#185), thanks @jwilk + 1.5.6 ===== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index a3f6f6b0..84ae78ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project(cJSON C) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 5) -set(PROJECT_VERSION_PATCH 6) +set(PROJECT_VERSION_PATCH 7) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 4d3fab34..0105a70b 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -15,6 +15,7 @@ Contributors * Ian Mobley * Irwan Djadjadi * [IvanVoid](https://github.com/npi3pak) +* [Jakub Wilk](https://github.com/jwilk) * [Jiri Zouhar](https://github.com/loigu) * [Jonathan Fether](https://github.com/jfether) * [Julián Vásquez](https://github.com/juvasquezg) diff --git a/Makefile b/Makefile index dca5e6ce..4ba05138 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.5.6 +LIBVERSION = 1.5.7 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 753b2156..93798ac5 100644 --- a/cJSON.c +++ b/cJSON.c @@ -58,7 +58,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 6) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 7) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index ef6e7651..0878fd0f 100644 --- a/cJSON.h +++ b/cJSON.h @@ -31,7 +31,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 5 -#define CJSON_VERSION_PATCH 6 +#define CJSON_VERSION_PATCH 7 #include From 2caa884f6a786c900754c25a19083e21db756b68 Mon Sep 17 00:00:00 2001 From: simon-p-r Date: Sat, 15 Jul 2017 09:03:13 +0100 Subject: [PATCH 056/307] removed x64 Visual Studio 9 2008 build --- .gitignore | 1 + appveyor-patch.ps1 | 13 ------------- appveyor.yml | 4 +++- 3 files changed, 4 insertions(+), 14 deletions(-) delete mode 100644 appveyor-patch.ps1 diff --git a/.gitignore b/.gitignore index 33424d90..e2e312b5 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ cJSON_test_utils libcjson.so.* libcjson_utils.so.* *.orig +.vscode diff --git a/appveyor-patch.ps1 b/appveyor-patch.ps1 deleted file mode 100644 index b380d53b..00000000 --- a/appveyor-patch.ps1 +++ /dev/null @@ -1,13 +0,0 @@ -# Script to patch Appveyor build environment for Visual Studio 2008 64bit - -$url = "https://github.com/menpo/condaci/raw/master/vs2008_patch.zip" -$output = "$pwd\build\vs2008_patch.zip" - -(New-Object System.Net.WebClient).DownloadFile($url, $output) - -7z -e "$pwd\build\vs2008_patch.zip" -cmd.exe /c "$pwd\build\vs2008_patch\setup_x64.bat" - -copy C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\amd64\vcvarsamd64.bat - - diff --git a/appveyor.yml b/appveyor.yml index f9c586af..e23eb64f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -66,13 +66,15 @@ environment: platform: - x86 - x64 + exclude: + - platform: x64 + GENERATOR: "Visual Studio 9 2008" configuration: - Release build_script: - - ps: if($env:PLATFORM -eq "x64" -And $GENERATOR -eq 'Visual Studio 9 2008') { .\appveyor-patch.ps1 } - ps: if($env:PLATFORM -eq "x64") { $env:CMAKE_GEN_SUFFIX=" Win64" } - cmake "-G%GENERATOR%%CMAKE_GEN_SUFFIX%" -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% -DENABLE_CJSON_TEST=%ENABLE_CJSON_TEST% -H. -Bbuild - cmake --build build --config "%CONFIGURATION%" From f0f3e55d485ece89153f947a5f57f3dbd8877958 Mon Sep 17 00:00:00 2001 From: simon-p-r Date: Sat, 15 Jul 2017 09:06:10 +0100 Subject: [PATCH 057/307] fixed appveyor script --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index e23eb64f..464bf038 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -66,6 +66,7 @@ environment: platform: - x86 - x64 +matrix: exclude: - platform: x64 GENERATOR: "Visual Studio 9 2008" From 469a437e2af3b965cafa038bdf17e5fbaa4d3a9e Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 15 Jul 2017 11:59:47 +0200 Subject: [PATCH 058/307] Add valgrind suppressions for ARVMv7 ArchlinuxARM --- tests/CMakeLists.txt | 2 +- valgrind.suppressions | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 valgrind.suppressions diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d69f3f82..b0b867ba 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -66,7 +66,7 @@ if(ENABLE_CJSON_TEST) message(WARNING "Valgrind couldn't be found.") unset(MEMORYCHECK_COMMAND) else() - set(MEMORYCHECK_COMMAND_OPTIONS --trace-children=yes --leak-check=full --error-exitcode=1) + set(MEMORYCHECK_COMMAND_OPTIONS --suppressions=${CMAKE_SOURCE_DIR}/valgrind.suppressions --trace-children=yes --leak-check=full --error-exitcode=1) endif() endif() diff --git a/valgrind.suppressions b/valgrind.suppressions new file mode 100644 index 00000000..7e5ac8ca --- /dev/null +++ b/valgrind.suppressions @@ -0,0 +1,11 @@ +{ + + Memcheck:Cond + fun:index + fun:expand_dynamic_string_token +} +{ + + Memcheck:Cond + fun:expand_dynamic_string_token +} From 76b705576f9743fd6ab5ba839c6689b37912ae90 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 21 Aug 2017 10:58:49 +0200 Subject: [PATCH 059/307] Makefile: Fix 'make test' make test tried to execute the test for cJSON_Utils, which has been ported to CUnity tests. --- Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 4ba05138..fb8244fb 100644 --- a/Makefile +++ b/Makefile @@ -66,11 +66,10 @@ shared: $(CJSON_SHARED) $(UTILS_SHARED) static: $(CJSON_STATIC) $(UTILS_STATIC) -tests: $(CJSON_TEST) $(UTILS_TEST) +tests: $(CJSON_TEST) test: tests ./$(CJSON_TEST) - ./$(UTILS_TEST) .c.o: $(CC) -c $(R_CFLAGS) $< @@ -150,4 +149,4 @@ clean: $(RM) $(CJSON_OBJ) $(UTILS_OBJ) #delete object files $(RM) $(CJSON_SHARED) $(CJSON_SHARED_VERSION) $(CJSON_SHARED_SO) $(CJSON_STATIC) #delete cJSON $(RM) $(UTILS_SHARED) $(UTILS_SHARED_VERSION) $(UTILS_SHARED_SO) $(UTILS_STATIC) #delete cJSON_Utils - $(RM) $(CJSON_TEST) $(UTILS_TEST) #delete tests + $(RM) $(CJSON_TEST) #delete test From 1925d1bbe596babd37dae5d9be694ff7327b6ee2 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 21 Aug 2017 11:06:10 +0200 Subject: [PATCH 060/307] Release version 1.5.8 --- CHANGELOG.md | 4 ++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a017d871..b98c9ed9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +1.5.8 +===== +* Fix `make test` in the Makefile, thanks @YanhaoMo for reporting this (#195) + 1.5.7 ===== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 84ae78ef..a51ec966 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project(cJSON C) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 5) -set(PROJECT_VERSION_PATCH 7) +set(PROJECT_VERSION_PATCH 8) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index fb8244fb..67b73c71 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.5.7 +LIBVERSION = 1.5.8 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 93798ac5..42481ed0 100644 --- a/cJSON.c +++ b/cJSON.c @@ -58,7 +58,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 7) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 8) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 0878fd0f..3a08b3a9 100644 --- a/cJSON.h +++ b/cJSON.h @@ -31,7 +31,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 5 -#define CJSON_VERSION_PATCH 7 +#define CJSON_VERSION_PATCH 8 #include From 1b2236a9a6cefe7cd4527361e910151e4d98b529 Mon Sep 17 00:00:00 2001 From: rmallins Date: Fri, 8 Sep 2017 01:20:52 +0100 Subject: [PATCH 061/307] Improve existing tests showing behaviour of Parse and ParseWithOpts functions. --- tests/parse_examples.c | 19 ++++++++++++++++++- tests/parse_with_opts.c | 21 +++++++++++++++++---- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/tests/parse_examples.c b/tests/parse_examples.c index 7562c457..76215bbc 100644 --- a/tests/parse_examples.c +++ b/tests/parse_examples.c @@ -142,7 +142,7 @@ static void file_test6_should_not_be_parsed(void) tree = cJSON_Parse(test6); TEST_ASSERT_NULL_MESSAGE(tree, "Should fail to parse what is not JSON."); - TEST_ASSERT_EQUAL_STRING_MESSAGE(test6, cJSON_GetErrorPtr(), "Error pointer is incorrect."); + TEST_ASSERT_EQUAL_PTR_MESSAGE(test6, cJSON_GetErrorPtr(), "Error pointer is incorrect."); if (test6 != NULL) { @@ -179,6 +179,22 @@ static void file_test11_should_be_parsed_and_printed(void) do_test("test11"); } +static void test12_should_not_be_parsed(void) +{ + const char *test12 = "{ \"name\": "; + cJSON *tree = NULL; + + tree = cJSON_Parse(test12); + TEST_ASSERT_NULL_MESSAGE(tree, "Should fail to parse incomplete JSON."); + + TEST_ASSERT_EQUAL_PTR_MESSAGE(test12 + strlen(test12), cJSON_GetErrorPtr(), "Error pointer is incorrect."); + + if (tree != NULL) + { + cJSON_Delete(tree); + } +} + int main(void) { UNITY_BEGIN(); @@ -193,5 +209,6 @@ int main(void) RUN_TEST(file_test9_should_be_parsed_and_printed); RUN_TEST(file_test10_should_be_parsed_and_printed); RUN_TEST(file_test11_should_be_parsed_and_printed); + RUN_TEST(test12_should_not_be_parsed); return UNITY_END(); } diff --git a/tests/parse_with_opts.c b/tests/parse_with_opts.c index 05574676..e75a69aa 100644 --- a/tests/parse_with_opts.c +++ b/tests/parse_with_opts.c @@ -40,11 +40,23 @@ static void parse_with_opts_should_handle_empty_strings(void) { const char empty_string[] = ""; const char *error_pointer = NULL; + TEST_ASSERT_NULL(cJSON_ParseWithOpts(empty_string, NULL, false)); - error_pointer = cJSON_GetErrorPtr(); - TEST_ASSERT_EQUAL_INT(0, error_pointer - empty_string); + TEST_ASSERT_EQUAL_PTR(empty_string, cJSON_GetErrorPtr()); + TEST_ASSERT_NULL(cJSON_ParseWithOpts(empty_string, &error_pointer, false)); - TEST_ASSERT_EQUAL_INT(0, error_pointer - empty_string); + TEST_ASSERT_EQUAL_PTR(empty_string, error_pointer); + TEST_ASSERT_EQUAL_PTR(NULL, cJSON_GetErrorPtr()); +} + +static void parse_with_opts_should_handle_incomplete_json(void) +{ + const char json[] = "{ \"name\": "; + const char *parse_end = NULL; + + TEST_ASSERT_NULL(cJSON_ParseWithOpts(json, &parse_end, false)); + TEST_ASSERT_EQUAL_PTR(json + strlen(json), parse_end); + TEST_ASSERT_NULL(cJSON_GetErrorPtr()); } static void parse_with_opts_should_require_null_if_requested(void) @@ -65,7 +77,7 @@ static void parse_with_opts_should_return_parse_end(void) cJSON *item = cJSON_ParseWithOpts(json, &parse_end, false); TEST_ASSERT_NOT_NULL(item); - TEST_ASSERT_EQUAL_INT(2, parse_end - json); + TEST_ASSERT_EQUAL_PTR(json + 2, parse_end); cJSON_Delete(item); } @@ -75,6 +87,7 @@ int main(void) RUN_TEST(parse_with_opts_should_handle_null); RUN_TEST(parse_with_opts_should_handle_empty_strings); + RUN_TEST(parse_with_opts_should_handle_incomplete_json); RUN_TEST(parse_with_opts_should_require_null_if_requested); RUN_TEST(parse_with_opts_should_return_parse_end); From 629c354390b5ed1984a37b87fea6cf47946fc83c Mon Sep 17 00:00:00 2001 From: rmallins Date: Wed, 6 Sep 2017 23:50:38 +0100 Subject: [PATCH 062/307] Rewrite test for cJSON_ParseWithOpts() to expect non-null error pointer in error case and change code to match new expectations. --- cJSON.c | 6 ++---- cJSON.h | 2 +- tests/parse_with_opts.c | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/cJSON.c b/cJSON.c index 42481ed0..1d1feea7 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1006,10 +1006,8 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return { *return_parse_end = (const char*)local_error.json + local_error.position; } - else - { - global_error = local_error; - } + + global_error = local_error; } return NULL; diff --git a/cJSON.h b/cJSON.h index 3a08b3a9..0be19b13 100644 --- a/cJSON.h +++ b/cJSON.h @@ -139,7 +139,7 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ -/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); /* Render a cJSON entity to text for transfer/storage. */ diff --git a/tests/parse_with_opts.c b/tests/parse_with_opts.c index e75a69aa..37a52e95 100644 --- a/tests/parse_with_opts.c +++ b/tests/parse_with_opts.c @@ -46,7 +46,7 @@ static void parse_with_opts_should_handle_empty_strings(void) TEST_ASSERT_NULL(cJSON_ParseWithOpts(empty_string, &error_pointer, false)); TEST_ASSERT_EQUAL_PTR(empty_string, error_pointer); - TEST_ASSERT_EQUAL_PTR(NULL, cJSON_GetErrorPtr()); + TEST_ASSERT_EQUAL_PTR(empty_string, cJSON_GetErrorPtr()); } static void parse_with_opts_should_handle_incomplete_json(void) @@ -56,7 +56,7 @@ static void parse_with_opts_should_handle_incomplete_json(void) TEST_ASSERT_NULL(cJSON_ParseWithOpts(json, &parse_end, false)); TEST_ASSERT_EQUAL_PTR(json + strlen(json), parse_end); - TEST_ASSERT_NULL(cJSON_GetErrorPtr()); + TEST_ASSERT_EQUAL_PTR(json + strlen(json), cJSON_GetErrorPtr()); } static void parse_with_opts_should_require_null_if_requested(void) From d92754cd304b7790c8e016293cb2e3002bd77e6d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 8 Sep 2017 13:19:41 +0200 Subject: [PATCH 063/307] Add valgrind suppressions for ARMv7 --- tests/CMakeLists.txt | 2 +- valgrind.supp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 valgrind.supp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 47d7c1a1..498758d9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -58,7 +58,7 @@ if(ENABLE_CJSON_TEST) message(WARNING "Valgrind couldn't be found.") unset(MEMORYCHECK_COMMAND) else() - set(MEMORYCHECK_COMMAND_OPTIONS --trace-children=yes --leak-check=full --error-exitcode=1) + set(MEMORYCHECK_COMMAND_OPTIONS --trace-children=yes --leak-check=full --error-exitcode=1 --suppressions=${CMAKE_CURRENT_SOURCE_DIR}/../valgrind.supp) endif() endif() diff --git a/valgrind.supp b/valgrind.supp new file mode 100644 index 00000000..79b55c67 --- /dev/null +++ b/valgrind.supp @@ -0,0 +1,6 @@ +{ + suppress_ld_on_armv7 + Memcheck:Cond + ... + obj:*/ld-*.so +} From 74566377938375bf127f06ee0bb11e282b13f0f6 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 8 Sep 2017 13:52:15 +0200 Subject: [PATCH 064/307] CONTRIBUTORS.md: Add Robin Mallinson --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 0105a70b..afbb1f9f 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -30,6 +30,7 @@ Contributors * [Pawel Winogrodzki](https://github.com/PawelWMS) * [prefetchnta](https://github.com/prefetchnta) * [Rafael Leal Dias](https://github.com/rafaeldias) +* [Robin Mallinson](https://github.com/rmallins) * [Rod Vagg](https://github.com/rvagg) * [Roland Meertens](https://github.com/rmeertens) * [Romain Porte](https://github.com/MicroJoe) From afd5d186b70e476309dc5c1df6a0222017b8ab41 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 8 Sep 2017 13:54:24 +0200 Subject: [PATCH 065/307] Release version 1.5.9 --- CHANGELOG.md | 4 ++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b98c9ed9..8e64552d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +1.5.9 +===== +* Set the global error pointer even if `return_parse_end` is passed to `cJSON_ParseWithOpts`. See #200, thanks @rmallins + 1.5.8 ===== * Fix `make test` in the Makefile, thanks @YanhaoMo for reporting this (#195) diff --git a/CMakeLists.txt b/CMakeLists.txt index a51ec966..68f3c5dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ project(cJSON C) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 5) -set(PROJECT_VERSION_PATCH 8) +set(PROJECT_VERSION_PATCH 9) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 67b73c71..38ca51a8 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.5.8 +LIBVERSION = 1.5.9 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 1d1feea7..306bb5b0 100644 --- a/cJSON.c +++ b/cJSON.c @@ -58,7 +58,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 8) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 9) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 0be19b13..1e388137 100644 --- a/cJSON.h +++ b/cJSON.h @@ -31,7 +31,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 5 -#define CJSON_VERSION_PATCH 8 +#define CJSON_VERSION_PATCH 9 #include From b7bfe1e91a0b55d72f849944d5a33b7962d7bf51 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 12 Sep 2017 18:30:07 +0200 Subject: [PATCH 066/307] Squashed 'tests/unity/' changes from 3b69bea..60b13f0 60b13f0 Bump version in preparation of release. f278c18 Fix bug #288 - invalid line numbers on partial name matches bdd4cb1 Merge pull request #294 from jlindgren90/master fcd4883 Fix compiler warning due to reusing symbol 'exp'. 05daf95 Update to match Ruby style guide 7b2ad10 Merge pull request #285 from dpostorivo/gt_lt_asserts 0547aab Merge pull request #291 from jlindgren90/master 2ae2bdb Make code C89-compliant. dbdd168 Fix test link error. 0e7eb54 Rewrite UnityPrintFloat to match printf("%.6g"). a868b2e Merge pull request #286 from palaviv/fix-UNITY_OUTPUT_FLUSH e56378e Add UNITY_OUTPUT_CHAR_HEADER_DECLARATION to fixture tests rakefile_helper.rb ad37302 Add UNITY_OUTPUT_CHAR_HEADER_DECLARATION to tests rakefile_helper.rb b3de931 Add UNITY_OUTPUT_CHAR_HEADER_DECLARATION to fixture tests Makefile defines 59182c4 Add UNITY_OUTPUT_CHAR_HEADER_DECLARATION to tests Makefile defines a07d07c Allow specifying custom header declaration c1bc32d - Generator will not change names by default - Fixed some style issues. f2fdf1a Added Greater than and Less than asserts from other PR git-subtree-dir: tests/unity git-subtree-split: 60b13f0685246b009810aecbffafe17fb665d970 --- README.md | 11 + auto/generate_module.rb | 6 +- auto/generate_test_runner.rb | 2 +- auto/stylize_as_junit.rb | 0 docs/UnityAssertionsReference.md | 54 +++ examples/unity_config.h | 10 +- extras/fixture/rakefile_helper.rb | 2 +- extras/fixture/test/Makefile | 1 + release/build.info | 2 +- release/version.info | 2 +- src/unity.c | 210 ++++++---- src/unity.h | 60 +++ src/unity_internals.h | 54 ++- test/Makefile | 1 + test/rakefile_helper.rb | 2 +- test/tests/testunity.c | 672 ++++++++++++++++++++++-------- 16 files changed, 825 insertions(+), 264 deletions(-) mode change 100644 => 100755 auto/stylize_as_junit.rb diff --git a/README.md b/README.md index 17ab5747..ec73b4a1 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,17 @@ Another way of calling TEST_ASSERT_EQUAL_INT Asserts that the actual value is within plus or minus delta of the expected value. This also comes in size specific variants. + + TEST_ASSERT_GREATER_THAN(threshold, actual) + +Asserts that the actual value is greater than the threshold. This also comes in size specific variants. + + + TEST_ASSERT_LESS_THAN(threshold, actual) + +Asserts that the actual value is less than the threshold. This also comes in size specific variants. + + Arrays ------ diff --git a/auto/generate_module.rb b/auto/generate_module.rb index ade4f1a9..13b4cc74 100644 --- a/auto/generate_module.rb +++ b/auto/generate_module.rb @@ -172,7 +172,7 @@ def create_filename(part1, part2 = '') when 'camel' then part1 when 'snake' then part1.downcase when 'caps' then part1.upcase - else part1.downcase + else part1 end else case (@options[:naming]) @@ -180,7 +180,7 @@ def create_filename(part1, part2 = '') when 'camel' then part1 + part2 when 'snake' then part1.downcase + '_' + part2.downcase when 'caps' then part1.upcase + '_' + part2.upcase - else part1.downcase + '_' + part2.downcase + else part1 + '_' + part2 end end end @@ -290,7 +290,7 @@ def destroy(module_name, pattern = nil) ' -n"camel" sets the file naming convention.', ' bumpy - BumpyCaseFilenames.', ' camel - camelCaseFilenames.', - ' snake - snake_case_filenames. (DEFAULT)', + ' snake - snake_case_filenames.', ' caps - CAPS_CASE_FILENAMES.', ' -u update subversion too (requires subversion command line)', ' -y"my.yml" selects a different yaml config file for module generation', diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index 2c5e56a9..07bde814 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -119,7 +119,7 @@ def find_tests(source) source_index = 0 tests_and_line_numbers.size.times do |i| source_lines[source_index..-1].each_with_index do |line, index| - next unless line =~ /#{tests_and_line_numbers[i][:test]}/ + next unless line =~ /\s+#{tests_and_line_numbers[i][:test]}(?:\s|\()/ source_index += index tests_and_line_numbers[i][:line_number] = source_index + 1 break diff --git a/auto/stylize_as_junit.rb b/auto/stylize_as_junit.rb old mode 100644 new mode 100755 diff --git a/docs/UnityAssertionsReference.md b/docs/UnityAssertionsReference.md index 558f6dbb..2dcf5e3a 100644 --- a/docs/UnityAssertionsReference.md +++ b/docs/UnityAssertionsReference.md @@ -290,6 +290,60 @@ Asserts the specified bit of the `actual` parameter is high. Asserts the specified bit of the `actual` parameter is low. +### Integer Less Than / Greater Than + +These assertions verify that the `actual` parameter is less than or greater +than `threshold` (exclusive). For example, if the threshold value is 0 for the +greater than assertion will fail if it is 0 or less. + +##### `TEST_ASSERT_GREATER_THAN (threshold, actual)` + +##### `TEST_ASSERT_GREATER_THAN_INT (threshold, actual)` + +##### `TEST_ASSERT_GREATER_THAN_INT8 (threshold, actual)` + +##### `TEST_ASSERT_GREATER_THAN_INT16 (threshold, actual)` + +##### `TEST_ASSERT_GREATER_THAN_INT32 (threshold, actual)` + +##### `TEST_ASSERT_GREATER_THAN_UINT (threshold, actual)` + +##### `TEST_ASSERT_GREATER_THAN_UINT8 (threshold, actual)` + +##### `TEST_ASSERT_GREATER_THAN_UINT16 (threshold, actual)` + +##### `TEST_ASSERT_GREATER_THAN_UINT32 (threshold, actual)` + +##### `TEST_ASSERT_GREATER_THAN_HEX8 (threshold, actual)` + +##### `TEST_ASSERT_GREATER_THAN_HEX16 (threshold, actual)` + +##### `TEST_ASSERT_GREATER_THAN_HEX32 (threshold, actual)` + +##### `TEST_ASSERT_LESS_THAN (threshold, actual)` + +##### `TEST_ASSERT_LESS_THAN_INT (threshold, actual)` + +##### `TEST_ASSERT_LESS_THAN_INT8 (threshold, actual)` + +##### `TEST_ASSERT_LESS_THAN_INT16 (threshold, actual)` + +##### `TEST_ASSERT_LESS_THAN_INT32 (threshold, actual)` + +##### `TEST_ASSERT_LESS_THAN_UINT (threshold, actual)` + +##### `TEST_ASSERT_LESS_THAN_UINT8 (threshold, actual)` + +##### `TEST_ASSERT_LESS_THAN_UINT16 (threshold, actual)` + +##### `TEST_ASSERT_LESS_THAN_UINT32 (threshold, actual)` + +##### `TEST_ASSERT_LESS_THAN_HEX8 (threshold, actual)` + +##### `TEST_ASSERT_LESS_THAN_HEX16 (threshold, actual)` + +##### `TEST_ASSERT_LESS_THAN_HEX32 (threshold, actual)` + ### Integer Ranges (of all sizes) diff --git a/examples/unity_config.h b/examples/unity_config.h index 355d9bf8..da3c2af1 100644 --- a/examples/unity_config.h +++ b/examples/unity_config.h @@ -201,10 +201,12 @@ * `stdout` option. You decide to route your test result output to a custom * serial `RS232_putc()` function you wrote like thus: */ -/* #define UNITY_OUTPUT_CHAR(a) RS232_putc(a) */ -/* #define UNITY_OUTPUT_FLUSH() RS232_flush() */ -/* #define UNITY_OUTPUT_START() RS232_config(115200,1,8,0) */ -/* #define UNITY_OUTPUT_COMPLETE() RS232_close() */ +/* #define UNITY_OUTPUT_CHAR(a) RS232_putc(a) */ +/* #define UNITY_OUTPUT_CHAR_HEADER_DECLARATION RS232_putc(int) */ +/* #define UNITY_OUTPUT_FLUSH() RS232_flush() */ +/* #define UNITY_OUTPUT_FLUSH_HEADER_DECLARATION RS232_flush(void) */ +/* #define UNITY_OUTPUT_START() RS232_config(115200,1,8,0) */ +/* #define UNITY_OUTPUT_COMPLETE() RS232_close() */ /* For some targets, Unity can make the otherwise required `setUp()` and * `tearDown()` functions optional. This is a nice convenience for test writers diff --git a/extras/fixture/rakefile_helper.rb b/extras/fixture/rakefile_helper.rb index 5aa8e56a..c45b2393 100644 --- a/extras/fixture/rakefile_helper.rb +++ b/extras/fixture/rakefile_helper.rb @@ -53,7 +53,7 @@ def build_compiler_fields defines = if $cfg['compiler']['defines']['items'].nil? '' else - squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'] + ['UNITY_OUTPUT_CHAR=UnityOutputCharSpy_OutputChar']) + squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'] + ['UNITY_OUTPUT_CHAR=UnityOutputCharSpy_OutputChar'] + ['UNITY_OUTPUT_CHAR_HEADER_DECLARATION=UnityOutputCharSpy_OutputChar\(int\)']) end options = squash('', $cfg['compiler']['options']) includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items']) diff --git a/extras/fixture/test/Makefile b/extras/fixture/test/Makefile index 80e124f4..e6c62552 100644 --- a/extras/fixture/test/Makefile +++ b/extras/fixture/test/Makefile @@ -6,6 +6,7 @@ endif CFLAGS += -std=c99 -pedantic -Wall -Wextra -Werror CFLAGS += $(DEBUG) DEFINES = -D UNITY_OUTPUT_CHAR=UnityOutputCharSpy_OutputChar +DEFINES += -D UNITY_OUTPUT_CHAR_HEADER_DECLARATION=UnityOutputCharSpy_OutputChar\(int\) SRC = ../src/unity_fixture.c \ ../../../src/unity.c \ unity_fixture_Test.c \ diff --git a/release/build.info b/release/build.info index 207634b2..50fb6eaf 100644 --- a/release/build.info +++ b/release/build.info @@ -1,2 +1,2 @@ -120 +121 diff --git a/release/version.info b/release/version.info index 3b904b68..b674b923 100644 --- a/release/version.info +++ b/release/version.info @@ -1,2 +1,2 @@ -2.4.1 +2.4.2 diff --git a/src/unity.c b/src/unity.c index 177af0f4..9783efac 100644 --- a/src/unity.c +++ b/src/unity.c @@ -27,6 +27,8 @@ static const char UnityStrNull[] = "NULL"; static const char UnityStrSpacer[] = ". "; static const char UnityStrExpected[] = " Expected "; static const char UnityStrWas[] = " Was "; +static const char UnityStrGt[] = " to be greater than "; +static const char UnityStrLt[] = " to be less than "; static const char UnityStrElement[] = " Element "; static const char UnityStrByte[] = " Byte "; static const char UnityStrMemory[] = " Memory Mismatch."; @@ -235,95 +237,97 @@ void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number) /*-----------------------------------------------*/ #ifndef UNITY_EXCLUDE_FLOAT_PRINT -static void UnityPrintDecimalAndNumberWithLeadingZeros(UNITY_INT32 fraction_part, UNITY_INT32 divisor) -{ - UNITY_OUTPUT_CHAR('.'); - while (divisor > 0) - { - UNITY_OUTPUT_CHAR('0' + fraction_part / divisor); - fraction_part %= divisor; - divisor /= 10; - if (fraction_part == 0) break; /* Truncate trailing 0's */ - } -} -#ifndef UNITY_ROUND_TIES_AWAY_FROM_ZERO -/* If rounds up && remainder 0.5 && result odd && below cutoff for double precision issues */ - #define ROUND_TIES_TO_EVEN(orig, num_int, num) \ - if (num_int > (num) && (num) - (num_int-1) <= 0.5 && (num_int & 1) == 1 && orig < 1e22) \ - num_int -= 1 /* => a tie to round down to even */ -#else - #define ROUND_TIES_TO_EVEN(orig, num_int, num) /* Remove macro */ -#endif - -/* Printing floating point numbers is hard. Some goals of this implementation: works for embedded - * systems, floats or doubles, and has a reasonable format. The key paper in this area, - * 'How to Print Floating-Point Numbers Accurately' by Steele & White, shows an approximation by - * scaling called Dragon 2. This code uses a similar idea. The other core algorithm uses casts and - * floating subtraction to give exact remainders after the decimal, to be scaled into an integer. - * Extra trailing 0's are excluded. The output defaults to rounding to nearest, ties to even. You - * can enable rounding ties away from zero. Note: UNITY_DOUBLE param can typedef to float or double - - * The old version required compiling in snprintf. For reference, with a similar format as now: - * char buf[19]; - * if (number > 4294967296.0 || -number > 4294967296.0) snprintf(buf, sizeof buf, "%.8e", number); - * else snprintf(buf, sizeof buf, "%.6f", number); - * UnityPrint(buf); - */ +/* This function prints a floating-point value in a format similar to + * printf("%.6g"). It can work with either single- or double-precision, + * but for simplicity, it prints only 6 significant digits in either case. + * Printing more than 6 digits accurately is hard (at least in the single- + * precision case) and isn't attempted here. */ void UnityPrintFloat(const UNITY_DOUBLE input_number) { - UNITY_DOUBLE number; + UNITY_DOUBLE number = input_number; - if (input_number < 0) + /* print minus sign (including for negative zero) */ + if (number < 0.0f || (number == 0.0f && 1.0f / number < 0.0f)) { UNITY_OUTPUT_CHAR('-'); - number = -input_number; - } else - { - number = input_number; + number = -number; } - if (isnan(number)) UnityPrint(UnityStrNaN); - else if (isinf(number)) UnityPrintLen(UnityStrInf, 3); - else if (number <= 0.0000005 && number > 0) UnityPrint("0.000000..."); /* Small number */ - else if (number < 4294967295.9999995) /* Rounded result fits in 32 bits, "%.6f" format */ + /* handle zero, NaN, and +/- infinity */ + if (number == 0.0f) UnityPrint("0"); + else if (isnan(number)) UnityPrint("nan"); + else if (isinf(number)) UnityPrint("inf"); + else { - const UNITY_INT32 divisor = 1000000/10; - UNITY_UINT32 integer_part = (UNITY_UINT32)number; - UNITY_INT32 fraction_part = (UNITY_INT32)((number - (UNITY_DOUBLE)integer_part)*1000000.0 + 0.5); - /* Double precision calculation gives best performance for six rounded decimal places */ - ROUND_TIES_TO_EVEN(number, fraction_part, (number - (UNITY_DOUBLE)integer_part)*1000000.0); + int exponent = 0; + int decimals, digits; + UNITY_INT32 n; + char buf[16]; + + /* scale up or down by powers of 10 */ + while (number < 100000.0f / 1e6f) { number *= 1e6f; exponent -= 6; } + while (number < 100000.0f) { number *= 10.0f; exponent--; } + while (number > 1000000.0f * 1e6f) { number /= 1e6f; exponent += 6; } + while (number > 1000000.0f) { number /= 10.0f; exponent++; } - if (fraction_part == 1000000) /* Carry across the decimal point */ + /* round to nearest integer */ + n = ((UNITY_INT32)(number + number) + 1) / 2; + if (n > 999999) { - fraction_part = 0; - integer_part += 1; + n = 100000; + exponent++; } - UnityPrintNumberUnsigned(integer_part); - UnityPrintDecimalAndNumberWithLeadingZeros(fraction_part, divisor); - } - else /* Number is larger, use exponential format of 9 digits, "%.8e" */ - { - const UNITY_INT32 divisor = 1000000000/10; - UNITY_INT32 integer_part; - UNITY_DOUBLE_TYPE divide = 10.0; - int exponent = 9; + /* determine where to place decimal point */ + decimals = (exponent <= 0 && exponent >= -9) ? -exponent : 5; + exponent += decimals; - while (number / divide >= 1000000000.0 - 0.5) + /* truncate trailing zeroes after decimal point */ + while (decimals > 0 && n % 10 == 0) { - divide *= 10; - exponent++; + n /= 10; + decimals--; + } + + /* build up buffer in reverse order */ + digits = 0; + while (n != 0 || digits < decimals + 1) + { + buf[digits++] = (char)('0' + n % 10); + n /= 10; + } + while (digits > 0) + { + if(digits == decimals) UNITY_OUTPUT_CHAR('.'); + UNITY_OUTPUT_CHAR(buf[--digits]); } - integer_part = (UNITY_INT32)(number / divide + 0.5); - /* Double precision calculation required for float, to produce 9 rounded digits */ - ROUND_TIES_TO_EVEN(number, integer_part, number / divide); - UNITY_OUTPUT_CHAR('0' + integer_part / divisor); - UnityPrintDecimalAndNumberWithLeadingZeros(integer_part % divisor, divisor / 10); - UNITY_OUTPUT_CHAR('e'); - UNITY_OUTPUT_CHAR('+'); - if (exponent < 10) UNITY_OUTPUT_CHAR('0'); - UnityPrintNumber(exponent); + /* print exponent if needed */ + if (exponent != 0) + { + UNITY_OUTPUT_CHAR('e'); + + if(exponent < 0) + { + UNITY_OUTPUT_CHAR('-'); + exponent = -exponent; + } + else + { + UNITY_OUTPUT_CHAR('+'); + } + + digits = 0; + while (exponent != 0 || digits < 2) + { + buf[digits++] = (char)('0' + exponent % 10); + exponent /= 10; + } + while (digits > 0) + { + UNITY_OUTPUT_CHAR(buf[--digits]); + } + } } } #endif /* ! UNITY_EXCLUDE_FLOAT_PRINT */ @@ -526,6 +530,50 @@ void UnityAssertEqualNumber(const UNITY_INT expected, } } +/*-----------------------------------------------*/ +void UnityAssertGreaterNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + RETURN_IF_FAIL_OR_IGNORE; + + if (!(actual > threshold)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(actual, style); + UnityPrint(UnityStrGt); + UnityPrintNumberByStyle(threshold, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +/*-----------------------------------------------*/ +void UnityAssertSmallerNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + RETURN_IF_FAIL_OR_IGNORE; + + if (!(actual < threshold)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(actual, style); + UnityPrint(UnityStrLt); + UnityPrintNumberByStyle(threshold, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + + + #define UnityPrintPointlessAndBail() \ { \ UnityTestResultsFailBegin(lineNumber); \ @@ -1025,7 +1073,7 @@ void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, { UNITY_UINT32 i = 0; UNITY_UINT32 j = 0; - const char* exp = NULL; + const char* expd = NULL; const char* act = NULL; RETURN_IF_FAIL_OR_IGNORE; @@ -1048,7 +1096,7 @@ void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, if (flags != UNITY_ARRAY_TO_ARRAY) { - exp = (const char*)expected; + expd = (const char*)expected; } do @@ -1056,15 +1104,15 @@ void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, act = actual[j]; if (flags == UNITY_ARRAY_TO_ARRAY) { - exp = ((const char* const*)expected)[j]; + expd = ((const char* const*)expected)[j]; } /* if both pointers not null compare the strings */ - if (exp && act) + if (expd && act) { - for (i = 0; exp[i] || act[i]; i++) + for (i = 0; expd[i] || act[i]; i++) { - if (exp[i] != act[i]) + if (expd[i] != act[i]) { Unity.CurrentTestFailed = 1; break; @@ -1073,7 +1121,7 @@ void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, } else { /* handle case of one pointers being null (if both null, test should pass) */ - if (exp != act) + if (expd != act) { Unity.CurrentTestFailed = 1; } @@ -1087,7 +1135,7 @@ void UnityAssertEqualStringArray(UNITY_INTERNAL_PTR expected, UnityPrint(UnityStrElement); UnityPrintNumberUnsigned(j); } - UnityPrintExpectedAndActualStrings(exp, act); + UnityPrintExpectedAndActualStrings(expd, act); UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } diff --git a/src/unity.h b/src/unity.h index 64342383..258e21c9 100644 --- a/src/unity.h +++ b/src/unity.h @@ -114,6 +114,35 @@ void tearDown(void); #define TEST_ASSERT_BIT_HIGH(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(-1), (actual), __LINE__, NULL) #define TEST_ASSERT_BIT_LOW(bit, actual) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, NULL) +/* Integer Greater Than/ Less Than (of all sizes) */ +#define TEST_ASSERT_GREATER_THAN(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, NULL) + + +#define TEST_ASSERT_LESS_THAN(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, NULL) + + /* Integer Ranges (of all sizes) */ #define TEST_ASSERT_INT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, NULL) #define TEST_ASSERT_INT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, NULL) @@ -157,6 +186,8 @@ void tearDown(void); #define TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, NULL) + + /* Arrays Compared To Single Value */ #define TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EACH_EQUAL_INT8(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT8((expected), (actual), (num_elements), __LINE__, NULL) @@ -241,6 +272,35 @@ void tearDown(void); #define TEST_ASSERT_BIT_HIGH_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(-1), (actual), __LINE__, (message)) #define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((UNITY_UINT32)1 << (bit)), (UNITY_UINT32)(0), (actual), __LINE__, (message)) +/* Integer Greater Than/ Less Than (of all sizes) */ +#define TEST_ASSERT_GREATER_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, (message)) + + +#define TEST_ASSERT_LESS_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, (message)) + + /* Integer Ranges (of all sizes) */ #define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, (message)) #define TEST_ASSERT_INT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT8_WITHIN((delta), (expected), (actual), __LINE__, (message)) diff --git a/src/unity_internals.h b/src/unity_internals.h index c08db955..1b57cd02 100644 --- a/src/unity_internals.h +++ b/src/unity_internals.h @@ -246,8 +246,8 @@ typedef UNITY_FLOAT_TYPE UNITY_FLOAT; #define UNITY_OUTPUT_CHAR(a) (void)putchar(a) #else /* If defined as something else, make sure we declare it here so it's ready for use */ - #ifndef UNITY_OMIT_OUTPUT_CHAR_HEADER_DECLARATION -extern void UNITY_OUTPUT_CHAR(int); + #ifdef UNITY_OUTPUT_CHAR_HEADER_DECLARATION +extern void UNITY_OUTPUT_CHAR_HEADER_DECLARATION; #endif #endif @@ -255,22 +255,22 @@ extern void UNITY_OUTPUT_CHAR(int); #ifdef UNITY_USE_FLUSH_STDOUT /* We want to use the stdout flush utility */ #include -#define UNITY_OUTPUT_FLUSH (void)fflush(stdout) +#define UNITY_OUTPUT_FLUSH() (void)fflush(stdout) #else /* We've specified nothing, therefore flush should just be ignored */ -#define UNITY_OUTPUT_FLUSH +#define UNITY_OUTPUT_FLUSH() #endif #else /* We've defined flush as something else, so make sure we declare it here so it's ready for use */ -#ifndef UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION -extern void UNITY_OUTPUT_FLUSH(void); +#ifdef UNITY_OUTPUT_FLUSH_HEADER_DECLARATION +extern void UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION; #endif #endif #ifndef UNITY_OUTPUT_FLUSH #define UNITY_FLUSH_CALL() #else -#define UNITY_FLUSH_CALL() UNITY_OUTPUT_FLUSH +#define UNITY_FLUSH_CALL() UNITY_OUTPUT_FLUSH() #endif #ifndef UNITY_PRINT_EOL @@ -455,6 +455,18 @@ void UnityAssertEqualNumber(const UNITY_INT expected, const UNITY_LINE_TYPE lineNumber, const UNITY_DISPLAY_STYLE_T style); +void UnityAssertGreaterNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityAssertSmallerNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, UNITY_INTERNAL_PTR actual, const UNITY_UINT32 num_elements, @@ -652,6 +664,34 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) #define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((UNITY_INT)(mask), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line)) + +#define UNITY_TEST_ASSERT_GREATER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) + + +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT8(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT16(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT32(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT8(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT16(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT32(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX8(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX16(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX32(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) + + + #define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) #define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) #define UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT16)(delta), (UNITY_INT)(UNITY_INT16)(expected), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) diff --git a/test/Makefile b/test/Makefile index 03b59bc4..9de7a49a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -14,6 +14,7 @@ CFLAGS += -Wbad-function-cast -Wcast-qual -Wold-style-definition -Wshadow -Wstri #DEBUG = -O0 -g CFLAGS += $(DEBUG) DEFINES = -D UNITY_OUTPUT_CHAR=putcharSpy +DEFINES += -D UNITY_OUTPUT_CHAR_HEADER_DECLARATION=putcharSpy\(int\) DEFINES += -D UNITY_SUPPORT_64 -D UNITY_INCLUDE_DOUBLE SRC = ../src/unity.c tests/testunity.c build/testunityRunner.c INC_DIR = -I ../src diff --git a/test/rakefile_helper.rb b/test/rakefile_helper.rb index be5bf3ea..1fd60c5f 100644 --- a/test/rakefile_helper.rb +++ b/test/rakefile_helper.rb @@ -91,7 +91,7 @@ def build_compiler_fields(inject_defines) defines = if $cfg['compiler']['defines']['items'].nil? '' else - squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'] + ['UNITY_OUTPUT_CHAR=putcharSpy'] + inject_defines) + squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'] + ['UNITY_OUTPUT_CHAR=putcharSpy'] + ['UNITY_OUTPUT_CHAR_HEADER_DECLARATION=putcharSpy\(int\)'] + inject_defines) end options = squash('', $cfg['compiler']['options']) includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items']) diff --git a/test/tests/testunity.c b/test/tests/testunity.c index 3555fb2d..af06647f 100644 --- a/test/tests/testunity.c +++ b/test/tests/testunity.c @@ -764,8 +764,9 @@ void testNotEqualBitsLow(void) EXPECT_ABORT_BEGIN TEST_ASSERT_BITS_LOW(v0, v1); VERIFY_FAILS_END - } + + void testEqualShorts(void) { short v0, v1; @@ -1305,6 +1306,415 @@ void testINT8sNotWithinDeltaAndCustomMessage(void) VERIFY_FAILS_END } + +//----------------- +void testGreaterThan(void) +{ + UNITY_INT v0, v1; + UNITY_INT *p0, *p1; + + v0 = 0; + v1 = 1; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_GREATER_THAN(v0, v1); + TEST_ASSERT_GREATER_THAN(*p0, v1); + TEST_ASSERT_GREATER_THAN(v0, *p1); + TEST_ASSERT_GREATER_THAN(*p0, *p1); +} + +void testGreaterThanINT(void) +{ + UNITY_INT v0, v1; + UNITY_INT *p0, *p1; + + v0 = 302; + v1 = 3334; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_GREATER_THAN_INT(v0, v1); + TEST_ASSERT_GREATER_THAN_INT(*p0, v1); + TEST_ASSERT_GREATER_THAN_INT(v0, *p1); + TEST_ASSERT_GREATER_THAN_INT(*p0, *p1); +} + + +void testGreaterThanINT8(void) +{ + UNITY_INT8 v0, v1; + UNITY_INT8 *p0, *p1; + + v0 = -128; + v1 = 127; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_GREATER_THAN_INT8(v0, v1); + TEST_ASSERT_GREATER_THAN_INT8(*p0, v1); + TEST_ASSERT_GREATER_THAN_INT8(v0, *p1); + TEST_ASSERT_GREATER_THAN_INT8(*p0, *p1); +} + +void testGreaterThanINT16(void) +{ + UNITY_INT16 v0, v1; + UNITY_INT16 *p0, *p1; + + v0 = -32768; + v1 = 32767; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_GREATER_THAN_INT16(v0, v1); + TEST_ASSERT_GREATER_THAN_INT16(*p0, v1); + TEST_ASSERT_GREATER_THAN_INT16(v0, *p1); + TEST_ASSERT_GREATER_THAN_INT16(*p0, *p1); +} + +void testGreaterThanINT32(void) +{ + UNITY_INT32 v0, v1; + UNITY_INT32 *p0, *p1; + + v0 = -214783648; + v1 = 214783647; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_GREATER_THAN_INT32(v0, v1); + TEST_ASSERT_GREATER_THAN_INT32(*p0, v1); + TEST_ASSERT_GREATER_THAN_INT32(v0, *p1); + TEST_ASSERT_GREATER_THAN_INT32(*p0, *p1); +} + +void testGreaterThanUINT(void) +{ + UNITY_UINT v0, v1; + UNITY_UINT *p0, *p1; + + v0 = 0; + v1 = 1; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_GREATER_THAN_UINT(v0, v1); + TEST_ASSERT_GREATER_THAN_UINT(*p0, v1); + TEST_ASSERT_GREATER_THAN_UINT(v0, *p1); + TEST_ASSERT_GREATER_THAN_UINT(*p0, *p1); +} + + +void testGreaterThanUINT8(void) +{ + UNITY_UINT8 v0, v1; + UNITY_UINT8 *p0, *p1; + + v0 = 0; + v1 = 255; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_GREATER_THAN_UINT8(v0, v1); + TEST_ASSERT_GREATER_THAN_UINT8(*p0, v1); + TEST_ASSERT_GREATER_THAN_UINT8(v0, *p1); + TEST_ASSERT_GREATER_THAN_UINT8(*p0, *p1); +} + +void testGreaterThanUINT16(void) +{ + UNITY_UINT16 v0, v1; + UNITY_UINT16 *p0, *p1; + + v0 = 0; + v1 = 65535; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_GREATER_THAN_UINT16(v0, v1); + TEST_ASSERT_GREATER_THAN_UINT16(*p0, v1); + TEST_ASSERT_GREATER_THAN_UINT16(v0, *p1); + TEST_ASSERT_GREATER_THAN_UINT16(*p0, *p1); +} + +void testGreaterThanUINT32(void) +{ + UNITY_UINT32 v0, v1; + UNITY_UINT32 *p0, *p1; + + v0 = 0; + v1 = 4294967295; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_GREATER_THAN_UINT32(v0, v1); + TEST_ASSERT_GREATER_THAN_UINT32(*p0, v1); + TEST_ASSERT_GREATER_THAN_UINT32(v0, *p1); + TEST_ASSERT_GREATER_THAN_UINT32(*p0, *p1); +} + +void testGreaterThanHEX8(void) +{ + UNITY_UINT8 v0, v1; + UNITY_UINT8 *p0, *p1; + + v0 = 0x00; + v1 = 0xFF; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_GREATER_THAN_HEX8(v0, v1); + TEST_ASSERT_GREATER_THAN_HEX8(*p0, v1); + TEST_ASSERT_GREATER_THAN_HEX8(v0, *p1); + TEST_ASSERT_GREATER_THAN_HEX8(*p0, *p1); +} + +void testGreaterThanHEX16(void) +{ + UNITY_UINT16 v0, v1; + UNITY_UINT16 *p0, *p1; + + v0 = 0x0000; + v1 = 0xFFFF; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_GREATER_THAN_HEX16(v0, v1); + TEST_ASSERT_GREATER_THAN_HEX16(*p0, v1); + TEST_ASSERT_GREATER_THAN_HEX16(v0, *p1); + TEST_ASSERT_GREATER_THAN_HEX16(*p0, *p1); +} + +void testGreaterThanHEX32(void) +{ + UNITY_UINT32 v0, v1; + UNITY_UINT32 *p0, *p1; + + v0 = 0x00000000; + v1 = 0xFFFFFFFF; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_GREATER_THAN_HEX32(v0, v1); + TEST_ASSERT_GREATER_THAN_HEX32(*p0, v1); + TEST_ASSERT_GREATER_THAN_HEX32(v0, *p1); + TEST_ASSERT_GREATER_THAN_HEX32(*p0, *p1); +} + + +void testNotGreaterThan(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_GREATER_THAN(0, -1); + VERIFY_FAILS_END +} + +void testLessThan(void) +{ + UNITY_INT v0, v1; + UNITY_INT *p0, *p1; + + v0 = 0; + v1 = -1; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_LESS_THAN(v0, v1); + TEST_ASSERT_LESS_THAN(*p0, v1); + TEST_ASSERT_LESS_THAN(v0, *p1); + TEST_ASSERT_LESS_THAN(*p0, *p1); +} + +void testLessThanINT(void) +{ + UNITY_INT v0, v1; + UNITY_INT *p0, *p1; + + v0 = 3334; + v1 = 302; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_LESS_THAN_INT(v0, v1); + TEST_ASSERT_LESS_THAN_INT(*p0, v1); + TEST_ASSERT_LESS_THAN_INT(v0, *p1); + TEST_ASSERT_LESS_THAN_INT(*p0, *p1); +} + + +void testLessThanINT8(void) +{ + UNITY_INT8 v0, v1; + UNITY_INT8 *p0, *p1; + + v0 = 127; + v1 = -128; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_LESS_THAN_INT8(v0, v1); + TEST_ASSERT_LESS_THAN_INT8(*p0, v1); + TEST_ASSERT_LESS_THAN_INT8(v0, *p1); + TEST_ASSERT_LESS_THAN_INT8(*p0, *p1); +} + +void testLessThanINT16(void) +{ + UNITY_INT16 v0, v1; + UNITY_INT16 *p0, *p1; + + v0 = 32767; + v1 = -32768; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_LESS_THAN_INT16(v0, v1); + TEST_ASSERT_LESS_THAN_INT16(*p0, v1); + TEST_ASSERT_LESS_THAN_INT16(v0, *p1); + TEST_ASSERT_LESS_THAN_INT16(*p0, *p1); +} + +void testLessThanINT32(void) +{ + UNITY_INT32 v0, v1; + UNITY_INT32 *p0, *p1; + + v0 = 214783647; + v1 = -214783648; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_LESS_THAN_INT32(v0, v1); + TEST_ASSERT_LESS_THAN_INT32(*p0, v1); + TEST_ASSERT_LESS_THAN_INT32(v0, *p1); + TEST_ASSERT_LESS_THAN_INT32(*p0, *p1); +} + +void testLessThanUINT(void) +{ + UNITY_UINT v0, v1; + UNITY_UINT *p0, *p1; + + v0 = 1; + v1 = 0; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_LESS_THAN_UINT(v0, v1); + TEST_ASSERT_LESS_THAN_UINT(*p0, v1); + TEST_ASSERT_LESS_THAN_UINT(v0, *p1); + TEST_ASSERT_LESS_THAN_UINT(*p0, *p1); +} + + +void testLessThanUINT8(void) +{ + UNITY_UINT8 v0, v1; + UNITY_UINT8 *p0, *p1; + + v0 = 255; + v1 = 0; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_LESS_THAN_UINT8(v0, v1); + TEST_ASSERT_LESS_THAN_UINT8(*p0, v1); + TEST_ASSERT_LESS_THAN_UINT8(v0, *p1); + TEST_ASSERT_LESS_THAN_UINT8(*p0, *p1); +} + +void testLessThanUINT16(void) +{ + UNITY_UINT16 v0, v1; + UNITY_UINT16 *p0, *p1; + + v0 = 65535; + v1 = 0; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_LESS_THAN_UINT16(v0, v1); + TEST_ASSERT_LESS_THAN_UINT16(*p0, v1); + TEST_ASSERT_LESS_THAN_UINT16(v0, *p1); + TEST_ASSERT_LESS_THAN_UINT16(*p0, *p1); +} + +void testLessThanUINT32(void) +{ + UNITY_UINT32 v0, v1; + UNITY_UINT32 *p0, *p1; + + v0 = 4294967295; + v1 = 0; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_LESS_THAN_UINT32(v0, v1); + TEST_ASSERT_LESS_THAN_UINT32(*p0, v1); + TEST_ASSERT_LESS_THAN_UINT32(v0, *p1); + TEST_ASSERT_LESS_THAN_UINT32(*p0, *p1); +} + +void testLessThanHEX8(void) +{ + UNITY_UINT8 v0, v1; + UNITY_UINT8 *p0, *p1; + + v0 = 0xFF; + v1 = 0x00; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_LESS_THAN_HEX8(v0, v1); + TEST_ASSERT_LESS_THAN_HEX8(*p0, v1); + TEST_ASSERT_LESS_THAN_HEX8(v0, *p1); + TEST_ASSERT_LESS_THAN_HEX8(*p0, *p1); +} + +void testLessThanHEX16(void) +{ + UNITY_UINT16 v0, v1; + UNITY_UINT16 *p0, *p1; + + v0 = 0xFFFF; + v1 = 0x0000; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_LESS_THAN_HEX16(v0, v1); + TEST_ASSERT_LESS_THAN_HEX16(*p0, v1); + TEST_ASSERT_LESS_THAN_HEX16(v0, *p1); + TEST_ASSERT_LESS_THAN_HEX16(*p0, *p1); +} + +void testLessThanHEX32(void) +{ + UNITY_UINT32 v0, v1; + UNITY_UINT32 *p0, *p1; + + v0 = 0xFFFFFFFF; + v1 = 0x00000000; + p0 = &v0; + p1 = &v1; + + TEST_ASSERT_LESS_THAN_HEX32(v0, v1); + TEST_ASSERT_LESS_THAN_HEX32(*p0, v1); + TEST_ASSERT_LESS_THAN_HEX32(v0, *p1); + TEST_ASSERT_LESS_THAN_HEX32(*p0, *p1); +} + + +void testNotLessThan(void) +{ + EXPECT_ABORT_BEGIN + TEST_ASSERT_LESS_THAN(0, 1); + VERIFY_FAILS_END +} + + + +//----------------- void testEqualStrings(void) { const char *testString = "foo"; @@ -4056,61 +4466,46 @@ void testFloatPrinting(void) #if defined(UNITY_EXCLUDE_FLOAT_PRINT) || !defined(USING_OUTPUT_SPY) TEST_IGNORE(); #else - TEST_ASSERT_EQUAL_PRINT_FLOATING("0.0", 0.0f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("0.000000...", 0.000000499f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("0.000001", 0.00000050000005f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("0.100469", 0.100469499f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("1.0", 0.9999995f); /*Rounding to int place*/ - TEST_ASSERT_EQUAL_PRINT_FLOATING("1.0", 1.0f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("1.25", 1.25f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("7.999999", 7.999999f); /*Not rounding*/ - TEST_ASSERT_EQUAL_PRINT_FLOATING("16.000002", 16.000002f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("16.000004", 16.000004f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("16.000006", 16.000006f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("4294967040.0", 4294967040.0f); /*Last full print integer*/ - - TEST_ASSERT_EQUAL_PRINT_FLOATING("0.0", -0.0f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-0.000000...",-0.000000499f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-0.000001", -0.00000050000005f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-0.100469", -0.100469499f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-1.0", -0.9999995f); /*Rounding to int place*/ - TEST_ASSERT_EQUAL_PRINT_FLOATING("-1.0", -1.0f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-1.25", -1.25f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-7.999999", -7.999999f); /*Not rounding*/ - TEST_ASSERT_EQUAL_PRINT_FLOATING("-16.000002", -16.000002f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-16.000004", -16.000004f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-16.000006", -16.000006f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-4294967040.0",-4294967040.0f); /*Last full print integer*/ - - TEST_ASSERT_EQUAL_PRINT_FLOATING("4.2949673e+09", 4294967296.0f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("5.0e+09", 5000000000.0f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("8.0e+09", 8.0e+09f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("8.3099991e+09", 8309999104.0f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("1.0e+10", 1.0e+10f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("1.0e+10", 10000000000.0f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("0", 0.0f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("4.99e-07", 0.000000499f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("5e-07", 0.00000050000005f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("0.100469", 0.100469499f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("1", 0.9999995f); /*Rounding to int place*/ + TEST_ASSERT_EQUAL_PRINT_FLOATING("1", 1.0f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("1.25", 1.25f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("7.99999", 7.99999f); /*Not rounding*/ + TEST_ASSERT_EQUAL_PRINT_FLOATING("16.0002", 16.0002f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("16.0004", 16.0004f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("16.0006", 16.0006f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("999999", 999999.0f); /*Last full print integer*/ + + TEST_ASSERT_EQUAL_PRINT_FLOATING("-0", -0.0f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-4.99e-07", -0.000000499f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-5e-07", -0.00000050000005f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-0.100469", -0.100469499f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-1", -0.9999995f); /*Rounding to int place*/ + TEST_ASSERT_EQUAL_PRINT_FLOATING("-1", -1.0f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-1.25", -1.25f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-7.99999", -7.99999f); /*Not rounding*/ + TEST_ASSERT_EQUAL_PRINT_FLOATING("-16.0002", -16.0002f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-16.0004", -16.0004f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-16.0006", -16.0006f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-999999", -999999.0f); /*Last full print integer*/ + + TEST_ASSERT_EQUAL_PRINT_FLOATING("4.29497e+09", 4294967296.0f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("5e+09", 5000000000.0f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("8e+09", 8.0e+09f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("8.31e+09", 8309999104.0f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("1e+10", 1.0e+10f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("1e+10", 10000000000.0f); /* Some compilers have trouble with inexact float constants, a float cast works generally */ - TEST_ASSERT_EQUAL_PRINT_FLOATING("1.00005499e+10", (float)1.000055e+10f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("1.10000006e+38", (float)1.10000005e+38f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("1.63529943e+10", 1.63529943e+10f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("3.40282347e+38", 3.40282346638e38f); - - TEST_ASSERT_EQUAL_PRINT_FLOATING("-1.0e+10", -1.0e+10f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-3.40282347e+38",-3.40282346638e38f); -#endif -} + TEST_ASSERT_EQUAL_PRINT_FLOATING("1.00005e+10", (float)1.000054e+10f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("1.1e+38", (float)1.10000005e+38f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("1.6353e+10", 1.63529943e+10f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("3.40282e+38", 3.40282346638e38f); -void testFloatPrintingRoundTiesToEven(void) -{ -#if defined(UNITY_EXCLUDE_FLOAT_PRINT) || !defined(USING_OUTPUT_SPY) - TEST_IGNORE(); -#else - #ifdef UNITY_ROUND_TIES_AWAY_FROM_ZERO - TEST_ASSERT_EQUAL_PRINT_FLOATING("0.007813", 0.0078125f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("0.976563", 0.9765625f); - #else /* Default to Round ties to even */ - TEST_ASSERT_EQUAL_PRINT_FLOATING("0.007182", 0.0071825f); - TEST_ASSERT_EQUAL_PRINT_FLOATING("0.976562", 0.9765625f); - #endif + TEST_ASSERT_EQUAL_PRINT_FLOATING("-1e+10", -1.0e+10f); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-3.40282e+38", -3.40282346638e38f); #endif } @@ -4119,105 +4514,69 @@ void testFloatPrintingInfinityAndNaN(void) #if defined(UNITY_EXCLUDE_FLOAT_PRINT) || !defined(USING_OUTPUT_SPY) TEST_IGNORE(); #else - TEST_ASSERT_EQUAL_PRINT_FLOATING("Inf", 1.0f / f_zero); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-Inf", -1.0f / f_zero); + TEST_ASSERT_EQUAL_PRINT_FLOATING("inf", 1.0f / f_zero); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-inf", -1.0f / f_zero); - TEST_ASSERT_EQUAL_PRINT_FLOATING("NaN", 0.0f / f_zero); + TEST_ASSERT_EQUAL_PRINT_FLOATING("nan", 0.0f / f_zero); #endif } #if defined(UNITY_TEST_ALL_FLOATS_PRINT_OK) && defined(USING_OUTPUT_SPY) -static void AllFloatPrinting_LessThan32Bits(void) +static void printFloatValue(float f) { char expected[18]; - union { float f_value; int32_t int_value; } u; - /* Float representations are laid out in integer order, walk up the list */ - for (u.f_value = 0.00000050000005f; u.f_value <= 4294967040.0f; u.int_value += 1) - { - startPutcharSpy(); - - UnityPrintFloat(u.f_value); /*1.5x as fast as sprintf 5e-7f - 0.01f, 20s vs 30s*/ - int len = sprintf(expected, "%.6f", u.f_value); - - while (expected[len - 1] == '0' && expected[len - 2] != '.') { len--; } - expected[len] = '\0'; /* delete trailing 0's */ - - if (strcmp(expected, getBufferPutcharSpy()) != 0) - { - double six_digits = ((double)u.f_value - (uint32_t)u.f_value)*1000000.0; - /* Not a tie (remainder != 0.5) => Can't explain the different strings */ - if (six_digits - (uint32_t)six_digits != 0.5) - { - /* Fail with diagnostic printing */ - TEST_ASSERT_EQUAL_PRINT_FLOATING(expected, u.f_value); - } - } - } -} + char expected_lower[18]; + char expected_higher[18]; -/* Compared to perfect, floats are occasionally rounded wrong. It doesn't affect - * correctness, though. Two examples (of 13 total found during testing): - * Printed: 6.19256349e+20, Exact: 619256348499999981568.0f <= Eliminated by ROUND_TIES_TO_EVEN - * Printed: 2.19012272e+35, Exact: 219012271499999993621766990196637696.0f */ -static void AllFloatPrinting_Larger(const float start, const float end) -{ - unsigned int wrong = 0; - char expected[18]; - union { float f_value; int32_t int_value; } u; - for (u.f_value = start; u.f_value <= end; u.int_value += 1) - { - startPutcharSpy(); + startPutcharSpy(); - UnityPrintFloat(u.f_value); /*Twice as fast as sprintf 2**32-1e12, 10s vs 21s*/ - sprintf(expected, "%.8e", u.f_value); + UnityPrintFloat(f); - int len = 11 - 1; /* 11th char is 'e' in exponential format */ - while (expected[len - 1] == '0' && expected[len - 2] != '.') { len --; } - if (expected[14] != '\0') memmove(&expected[12], &expected[13], 3); /* Two char exponent */ - memmove(&expected[len], &expected[11 - 1], sizeof "e+09"); /* 5 char length */ + sprintf(expected, "%.6g", f); - if (strcmp(expected, getBufferPutcharSpy()) != 0) - { - wrong++; - /* endPutcharSpy(); UnityPrint("Expected "); UnityPrint(expected); - UnityPrint(" Was "); UnityPrint(getBufferPutcharSpy()); UNITY_OUTPUT_CHAR('\n'); */ + /* We print all NaN's as "nan", not "-nan" */ + if(strcmp(expected, "-nan") == 0) strcpy(expected, "nan"); - if (wrong > 10 || (wrong > 3 && end <= 1e25f)) - TEST_ASSERT_EQUAL_PRINT_FLOATING(expected, u.f_value); - /* Empirical values from the current routine, don't be worse when making changes */ - } + /* Allow for rounding differences in last digit */ + double lower = (double)f * 0.9999995; + double higher = (double)f * 1.0000005; + + if (isfinite(lower)) sprintf(expected_lower, "%.6g", lower); else strcpy(expected_lower, expected); + if (isfinite(higher)) sprintf(expected_higher, "%.6g", higher); else strcpy(expected_higher, expected); + + if (strcmp(expected, getBufferPutcharSpy()) != 0 && + strcmp(expected_lower, getBufferPutcharSpy()) != 0 && + strcmp(expected_higher, getBufferPutcharSpy()) != 0) + { + /* Fail with diagnostic printing */ + TEST_ASSERT_EQUAL_PRINT_FLOATING(expected, f); } } #endif -/* Exhaustive testing of all float values we differentiate when printing. Doubles - * are not explored here -- too many. These tests confirm that the routine works - * for all floats > 5e-7, positives only. Off by default due to test time. - * Compares Unity's routine to your sprintf() C lib, tested to pass on 3 platforms. - * Part1 takes a long time, around 3 minutes compiled with -O2 - * Runs through all floats from 0.000001 - 2**32, ~300 million values */ -void testAllFloatPrintingPart1_LessThan32Bits(void) +void testFloatPrintingRandomSamples(void) { -#if defined(UNITY_TEST_ALL_FLOATS_PRINT_OK) && defined(USING_OUTPUT_SPY) - AllFloatPrinting_LessThan32Bits(); +#if !defined(UNITY_TEST_ALL_FLOATS_PRINT_OK) || !defined(USING_OUTPUT_SPY) + TEST_IGNORE(); #else - TEST_IGNORE(); /* Ignore one of three */ -#endif -} + union { float f_value; uint32_t int_value; } u; -/* Test takes a long time, around 3.5 minutes compiled with -O2, try ~500 million values */ -void testAllFloatPrintingPart2_Larger(void) -{ -#if defined(UNITY_TEST_ALL_FLOATS_PRINT_OK) && defined(USING_OUTPUT_SPY) - AllFloatPrinting_Larger(4294967296.0f, 1e25f); -#endif -} + /* These values are not covered by the MINSTD generator */ + u.int_value = 0x00000000; printFloatValue(u.f_value); + u.int_value = 0x80000000; printFloatValue(u.f_value); + u.int_value = 0x7fffffff; printFloatValue(u.f_value); + u.int_value = 0xffffffff; printFloatValue(u.f_value); -/* Test takes a long time, around 3.5 minutes compiled with -O2, try ~500 million values */ -void testAllFloatPrintingPart3_LargerStill(void) -{ -#if defined(UNITY_TEST_ALL_FLOATS_PRINT_OK) && defined(USING_OUTPUT_SPY) - AllFloatPrinting_Larger(1e25f, 3.40282347e+38f); + uint32_t a = 1; + for(int num_tested = 0; num_tested < 1000000; num_tested++) + { + /* MINSTD pseudo-random number generator */ + a = (uint32_t)(((uint64_t)a * 48271u) % 2147483647u); + + /* MINSTD does not set the highest bit; test both possibilities */ + u.int_value = a; printFloatValue(u.f_value); + u.int_value = a | 0x80000000; printFloatValue(u.f_value); + } #endif } @@ -4893,35 +5252,20 @@ void testDoublePrinting(void) #if defined(UNITY_EXCLUDE_FLOAT_PRINT) || defined(UNITY_EXCLUDE_DOUBLE) || !defined(USING_OUTPUT_SPY) TEST_IGNORE(); #else - TEST_ASSERT_EQUAL_PRINT_FLOATING("0.100469", 0.10046949999999999); - TEST_ASSERT_EQUAL_PRINT_FLOATING("4294967295.999999", 4294967295.999999); - TEST_ASSERT_EQUAL_PRINT_FLOATING("4.2949673e+09", 4294967295.9999995); - TEST_ASSERT_EQUAL_PRINT_FLOATING("4.2949673e+09", 4294967296.0); - TEST_ASSERT_EQUAL_PRINT_FLOATING("1.0e+10", 9999999995.0); - TEST_ASSERT_EQUAL_PRINT_FLOATING("9.00719925e+15", 9007199254740990.0); - TEST_ASSERT_EQUAL_PRINT_FLOATING("7.0e+100", 7.0e+100); - TEST_ASSERT_EQUAL_PRINT_FLOATING("3.0e+200", 3.0e+200); - TEST_ASSERT_EQUAL_PRINT_FLOATING("9.23456789e+300", 9.23456789e+300); + TEST_ASSERT_EQUAL_PRINT_FLOATING("0.100469", 0.10046949999999999); + TEST_ASSERT_EQUAL_PRINT_FLOATING("4.29497e+09", 4294967295.999999); + TEST_ASSERT_EQUAL_PRINT_FLOATING("4.29497e+09", 4294967295.9999995); + TEST_ASSERT_EQUAL_PRINT_FLOATING("4.29497e+09", 4294967296.0); + TEST_ASSERT_EQUAL_PRINT_FLOATING("1e+10", 9999999995.0); + TEST_ASSERT_EQUAL_PRINT_FLOATING("9.0072e+15", 9007199254740990.0); + TEST_ASSERT_EQUAL_PRINT_FLOATING("7e+100", 7.0e+100); + TEST_ASSERT_EQUAL_PRINT_FLOATING("3e+200", 3.0e+200); + TEST_ASSERT_EQUAL_PRINT_FLOATING("9.23457e+300", 9.23456789e+300); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-0.100469", -0.10046949999999999); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-4294967295.999999", -4294967295.999999); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-4.2949673e+09", -4294967295.9999995); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-7.0e+100", -7.0e+100); -#endif -} - -void testDoublePrintingRoundTiesToEven(void) -{ -#if defined(UNITY_EXCLUDE_FLOAT_PRINT) || defined(UNITY_EXCLUDE_DOUBLE) || !defined(USING_OUTPUT_SPY) - TEST_IGNORE(); -#else - #ifdef UNITY_ROUND_TIES_AWAY_FROM_ZERO - TEST_ASSERT_EQUAL_PRINT_FLOATING("1.00000001e+10", 10000000050.0); - TEST_ASSERT_EQUAL_PRINT_FLOATING("9.00719925e+15", 9007199245000000.0); - #else /* Default to Round ties to even */ - TEST_ASSERT_EQUAL_PRINT_FLOATING("1.0e+10", 10000000050.0); - TEST_ASSERT_EQUAL_PRINT_FLOATING("9.00719924e+15", 9007199245000000.0); - #endif + TEST_ASSERT_EQUAL_PRINT_FLOATING("-0.100469", -0.10046949999999999); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-4.29497e+09", -4294967295.999999); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-4.29497e+09", -4294967295.9999995); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-7e+100", -7.0e+100); #endif } @@ -4930,10 +5274,10 @@ void testDoublePrintingInfinityAndNaN(void) #if defined(UNITY_EXCLUDE_FLOAT_PRINT) || defined(UNITY_EXCLUDE_DOUBLE) || !defined(USING_OUTPUT_SPY) TEST_IGNORE(); #else - TEST_ASSERT_EQUAL_PRINT_FLOATING("Inf", 1.0 / d_zero); - TEST_ASSERT_EQUAL_PRINT_FLOATING("-Inf", -1.0 / d_zero); + TEST_ASSERT_EQUAL_PRINT_FLOATING("inf", 1.0 / d_zero); + TEST_ASSERT_EQUAL_PRINT_FLOATING("-inf", -1.0 / d_zero); - TEST_ASSERT_EQUAL_PRINT_FLOATING("NaN", 0.0 / d_zero); + TEST_ASSERT_EQUAL_PRINT_FLOATING("nan", 0.0 / d_zero); #endif } From 4f9e9dfc3089896079d42115fcff354d1565baac Mon Sep 17 00:00:00 2001 From: casperinous Date: Sun, 8 Oct 2017 21:55:58 +0300 Subject: [PATCH 067/307] Fix for issue #202, regarding the lack of implementation of the localeconv method in some SDK's. A macro named `ENABLE_LOCALES` was added and an option with the same name too in the CMakeLists.txt --- CMakeLists.txt | 6 ++++++ README.md | 1 + cJSON.c | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 68f3c5dd..e3b8d7a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,5 +186,11 @@ if(ENABLE_CJSON_TEST) DEPENDS ${TEST_CJSON}) endif() +# Enable the use of locales +option(ENABLE_LOCALES "Enable the use of locales" ON) +if(ENABLE_LOCALES) + add_definitions(-DENABLE_LOCALES) +endif() + add_subdirectory(tests) add_subdirectory(fuzzing) diff --git a/README.md b/README.md index 4dba514a..121e7305 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ You can change the build process with a list of different options that you can p * `-DENABLE_SANITIZERS=On`: Compile cJSON with [AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) and [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) enabled (if possible). (off by default) * `-DBUILD_SHARED_LIBS=On`: Build the shared libraries. (on by default) * `-DCMAKE_INSTALL_PREFIX=/usr`: Set a prefix for the installation. +* `-DENABLE_LOCALES=On`: Enable the usage of localeconv method. ( on by default ) If you are packaging cJSON for a distribution of Linux, you would probably take these steps for example: ``` diff --git a/cJSON.c b/cJSON.c index 306bb5b0..18b52b55 100644 --- a/cJSON.c +++ b/cJSON.c @@ -193,8 +193,12 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) /* get the decimal point character of the current locale */ static unsigned char get_decimal_point(void) { +#ifdef ENABLE_LOCALES struct lconv *lconv = localeconv(); return (unsigned char) lconv->decimal_point[0]; +#else + return '.'; +#endif } typedef struct From 9b960fa870f3f7d754ccb048e51780f7150f970b Mon Sep 17 00:00:00 2001 From: casperinous Date: Sun, 8 Oct 2017 22:02:52 +0300 Subject: [PATCH 068/307] Small indentation fix in order to follow the contribution rules. --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 18b52b55..fa143cc4 100644 --- a/cJSON.c +++ b/cJSON.c @@ -197,7 +197,7 @@ static unsigned char get_decimal_point(void) struct lconv *lconv = localeconv(); return (unsigned char) lconv->decimal_point[0]; #else - return '.'; + return '.'; #endif } From c51a19be51e44843f807b6d86fcb345fc56f3c84 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 8 Oct 2017 22:05:19 +0200 Subject: [PATCH 069/307] CONTRIBUTING.md: Fix '4 tabs' -> '4 spaces' --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 172cfcd3..83d2e599 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -15,7 +15,7 @@ Coding Style ------------ The coding style has been discussed in [#24](https://github.com/DaveGamble/cJSON/issues/24). The basics are: -* Use 4 tabs for indentation +* Use 4 spaces for indentation * No oneliners (conditions, loops, variable declarations ...) * Always use parenthesis for control structures * Don't implicitly rely on operator precedence, use round brackets in expressions. e.g. `(a > b) && (c < d)` instead of `a>b && c Date: Sun, 8 Oct 2017 23:13:30 +0200 Subject: [PATCH 070/307] Contributors: Add Simon Ricaldone and Casperinous --- CONTRIBUTORS.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index afbb1f9f..2f858504 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,11 +1,14 @@ Contributors ============ +Original Author: [Dave Gamble](https://github.com/DaveGamble) +Current Maintainer: [Max Bruckner](https://github.com/FSMaxB) + * [Ajay Bhargav](https://github.com/ajaybhargav) * [Alper Akcan](https://github.com/alperakcan) * [Anton Sergeev](https://github.com/anton-sergeev) * [Christian Schulze](https://github.com/ChristianSch) -* [Dave Gamble](https://github.com/DaveGamble) +* [Casperinous](https://github.com/Casperinous) * [Debora Grosse](https://github.com/DeboraG) * [dieyushi](https://github.com/dieyushi) * [Dōngwén Huáng (黄东文)](https://github.com/DongwenHuang) @@ -22,7 +25,6 @@ Contributors * [Kevin Branigan](https://github.com/kbranigan) * [Kyle Chisholm](https://github.com/ChisholmKyle) * [Linus Wallgren](https://github.com/ecksun) -* [Max Bruckner](https://github.com/FSMaxB) * Mike Pontillo * [Mike Jerris](https://github.com/mjerris) * [Mike Robinson](https://github.com/mhrobinson) @@ -34,6 +36,7 @@ Contributors * [Rod Vagg](https://github.com/rvagg) * [Roland Meertens](https://github.com/rmeertens) * [Romain Porte](https://github.com/MicroJoe) +* [Simon Ricaldone](https://github.com/simon-p-r) * [Stephan Gatzka](https://github.com/gatzka) * [Weston Schmidt](https://github.com/schmidtw) From 96c33e5abbc45ebff2082f380120259dd74b63a2 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 8 Oct 2017 23:28:49 +0200 Subject: [PATCH 071/307] ENABLE_LOCALES: Actually disable the include as well --- cJSON.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cJSON.c b/cJSON.c index d5e01f1a..5816f7ff 100644 --- a/cJSON.c +++ b/cJSON.c @@ -44,7 +44,10 @@ #include #include #include + +#ifdef ENABLE_LOCALES #include +#endif #if defined(_MSC_VER) #pragma warning (pop) From c083421f408f0ee5012dca431baefe8791858a33 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 8 Oct 2017 23:36:41 +0200 Subject: [PATCH 072/307] Release version 1.6.0 --- CHANGELOG.md | 15 +++++++++++++++ CMakeLists.txt | 4 ++-- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 4 ++-- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e64552d..a7856838 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,18 @@ +1.6.0 +===== +Features: +--------- +* You can now build cJSON as both shared and static library at once with CMake using `-DBUILD_SHARED_AND_STATIC_LIBS=On`, see #178 +* UTF-8 byte order marks are now ignored, see #184 +* Locales can now be disabled with the option `-DENABLE_LOCALES=Off`, see #202, thanks @Casperinous +* Better support for MSVC and Visual Studio + +Other Changes: +-------------- +* Add the new warnings `-Wswitch-enum`, `-Wused-but-makred-unused`, `-Wmissing-variable-declarations`, `-Wunused-macro` +* More number printing tests. +* Continuous integration testing with AppVeyor (semi automatic at this point), thanks @simon-p-r + 1.5.9 ===== * Set the global error pointer even if `return_parse_end` is passed to `cJSON_ParseWithOpts`. See #200, thanks @rmallins diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a28a682..47ff6a2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,8 @@ include(GNUInstallDirs) project(cJSON C) set(PROJECT_VERSION_MAJOR 1) -set(PROJECT_VERSION_MINOR 5) -set(PROJECT_VERSION_PATCH 9) +set(PROJECT_VERSION_MINOR 6) +set(PROJECT_VERSION_PATCH 0) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 38ca51a8..2d472078 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.5.9 +LIBVERSION = 1.6.0 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 5816f7ff..84559ef8 100644 --- a/cJSON.c +++ b/cJSON.c @@ -74,7 +74,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 9) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 6) || (CJSON_VERSION_PATCH != 0) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 1e388137..7c4f8e7c 100644 --- a/cJSON.h +++ b/cJSON.h @@ -30,8 +30,8 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 -#define CJSON_VERSION_MINOR 5 -#define CJSON_VERSION_PATCH 9 +#define CJSON_VERSION_MINOR 6 +#define CJSON_VERSION_PATCH 0 #include From df1c49dba152249011670cac26e47b1bab9dd666 Mon Sep 17 00:00:00 2001 From: yangfl Date: Sat, 4 Nov 2017 17:39:54 +0800 Subject: [PATCH 073/307] CMakeLists.txt: swap GNUInstallDirs and project --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47ff6a2f..1db8281b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0) cmake_minimum_required(VERSION 2.8.5) -include(GNUInstallDirs) - project(cJSON C) +include(GNUInstallDirs) + set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 6) set(PROJECT_VERSION_PATCH 0) From 35907223e11010e89dee11d48c7fdeecd491bc8f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 4 Nov 2017 13:39:58 +0100 Subject: [PATCH 074/307] README: Explain including cJSON, fix #211 --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 161ab170..deb62100 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,13 @@ make all If you want, you can install the compiled library to your system using `make install`. By default it will install the headers in `/usr/local/include/cjson` and the libraries in `/usr/local/lib`. But you can change this behavior by setting the `PREFIX` and `DESTDIR` variables: `make PREFIX=/usr DESTDIR=temp install`. +### Including cJSON +If you installed it via the CMake or the Makefile, you can include cJSON like this: + +```c +#include +``` + ### Some JSON: ```json From 8412b1e2cd0e497d3ed4e590565c70c0b0efc10b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 4 Nov 2017 13:42:20 +0100 Subject: [PATCH 075/307] README: fixup last commit --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index deb62100..ddfea3f4 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Ultralightweight JSON parser in ANSI C. * [Usage](#usage) * [Welcome to cJSON](#welcome-to-cjson) * [Building](#building) + * [Including cJSON](#including-cjson) * [Some JSON](#some-json) * [Here's the structure](#heres-the-structure) * [Caveats](#caveats) @@ -115,7 +116,7 @@ make all If you want, you can install the compiled library to your system using `make install`. By default it will install the headers in `/usr/local/include/cjson` and the libraries in `/usr/local/lib`. But you can change this behavior by setting the `PREFIX` and `DESTDIR` variables: `make PREFIX=/usr DESTDIR=temp install`. ### Including cJSON -If you installed it via the CMake or the Makefile, you can include cJSON like this: +If you installed it via CMake or the Makefile, you can include cJSON like this: ```c #include From fa00278f661644b37d43c96a290b8ce198e07511 Mon Sep 17 00:00:00 2001 From: yangfl Date: Sat, 4 Nov 2017 20:23:37 +0800 Subject: [PATCH 076/307] Remove trailing space --- CMakeLists.txt | 2 +- LICENSE | 38 +++++++++++++++++++------------------- cJSON.c | 2 +- fuzzing/inputs/test11 | 8 ++++---- fuzzing/inputs/test3 | 4 ++-- fuzzing/inputs/test3.bu | 4 ++-- fuzzing/inputs/test3.uf | 4 ++-- fuzzing/inputs/test3.uu | 4 ++-- fuzzing/inputs/test4 | 6 +++--- tests/inputs/test11 | 8 ++++---- tests/inputs/test3 | 4 ++-- tests/inputs/test4 | 6 +++--- 12 files changed, 45 insertions(+), 45 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1db8281b..24132562 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -238,7 +238,7 @@ endif() option(ENABLE_LOCALES "Enable the use of locales" ON) if(ENABLE_LOCALES) add_definitions(-DENABLE_LOCALES) -endif() +endif() add_subdirectory(tests) add_subdirectory(fuzzing) diff --git a/LICENSE b/LICENSE index b15182d0..78deb040 100644 --- a/LICENSE +++ b/LICENSE @@ -1,20 +1,20 @@ - Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. +Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/cJSON.c b/cJSON.c index 84559ef8..cef719f5 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1062,7 +1062,7 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return { *return_parse_end = (const char*)local_error.json + local_error.position; } - + global_error = local_error; } diff --git a/fuzzing/inputs/test11 b/fuzzing/inputs/test11 index 818c6e0f..e81d60d7 100644 --- a/fuzzing/inputs/test11 +++ b/fuzzing/inputs/test11 @@ -1,8 +1,8 @@ bf{ -"name": "Jack (\"Bee\") Nimble", -"format": {"type": "rect", -"width": 1920, -"height": 1080, +"name": "Jack (\"Bee\") Nimble", +"format": {"type": "rect", +"width": 1920, +"height": 1080, "interlace": false,"frame rate": 24 } } diff --git a/fuzzing/inputs/test3 b/fuzzing/inputs/test3 index 7143163b..11edd2f2 100644 --- a/fuzzing/inputs/test3 +++ b/fuzzing/inputs/test3 @@ -6,7 +6,7 @@ bf{"widget": { "width": 500, "height": 500 }, - "image": { + "image": { "src": "Images/Sun.png", "name": "sun1", "hOffset": 250, @@ -23,4 +23,4 @@ bf{"widget": { "alignment": "center", "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" } -}} +}} diff --git a/fuzzing/inputs/test3.bu b/fuzzing/inputs/test3.bu index 6fc93d3c..eaac4e31 100644 --- a/fuzzing/inputs/test3.bu +++ b/fuzzing/inputs/test3.bu @@ -6,7 +6,7 @@ bu{"widget": { "width": 500, "height": 500 }, - "image": { + "image": { "src": "Images/Sun.png", "name": "sun1", "hOffset": 250, @@ -23,4 +23,4 @@ bu{"widget": { "alignment": "center", "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" } -}} +}} diff --git a/fuzzing/inputs/test3.uf b/fuzzing/inputs/test3.uf index d48df612..edad9778 100644 --- a/fuzzing/inputs/test3.uf +++ b/fuzzing/inputs/test3.uf @@ -6,7 +6,7 @@ uf{"widget": { "width": 500, "height": 500 }, - "image": { + "image": { "src": "Images/Sun.png", "name": "sun1", "hOffset": 250, @@ -23,4 +23,4 @@ uf{"widget": { "alignment": "center", "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" } -}} +}} diff --git a/fuzzing/inputs/test3.uu b/fuzzing/inputs/test3.uu index ad6ae541..1356b6d9 100644 --- a/fuzzing/inputs/test3.uu +++ b/fuzzing/inputs/test3.uu @@ -6,7 +6,7 @@ uu{"widget": { "width": 500, "height": 500 }, - "image": { + "image": { "src": "Images/Sun.png", "name": "sun1", "hOffset": 250, @@ -23,4 +23,4 @@ uu{"widget": { "alignment": "center", "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" } -}} +}} diff --git a/fuzzing/inputs/test4 b/fuzzing/inputs/test4 index e24ae9b3..943943d2 100644 --- a/fuzzing/inputs/test4 +++ b/fuzzing/inputs/test4 @@ -1,5 +1,5 @@ bf{"web-app": { - "servlet": [ + "servlet": [ { "servlet-name": "cofaxCDS", "servlet-class": "org.cofax.cds.CDSServlet", @@ -55,7 +55,7 @@ bf{"web-app": { { "servlet-name": "cofaxAdmin", "servlet-class": "org.cofax.cds.AdminServlet"}, - + { "servlet-name": "fileServlet", "servlet-class": "org.cofax.cds.FileServlet"}, @@ -82,7 +82,7 @@ bf{"web-app": { "cofaxAdmin": "/admin/*", "fileServlet": "/static/*", "cofaxTools": "/tools/*"}, - + "taglib": { "taglib-uri": "cofax.tld", "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} diff --git a/tests/inputs/test11 b/tests/inputs/test11 index eaf43e6e..039c61b9 100644 --- a/tests/inputs/test11 +++ b/tests/inputs/test11 @@ -1,8 +1,8 @@ { -"name": "Jack (\"Bee\") Nimble", -"format": {"type": "rect", -"width": 1920, -"height": 1080, +"name": "Jack (\"Bee\") Nimble", +"format": {"type": "rect", +"width": 1920, +"height": 1080, "interlace": false,"frame rate": 24 } } diff --git a/tests/inputs/test3 b/tests/inputs/test3 index 5662b377..7f74acaa 100644 --- a/tests/inputs/test3 +++ b/tests/inputs/test3 @@ -6,7 +6,7 @@ "width": 500, "height": 500 }, - "image": { + "image": { "src": "Images/Sun.png", "name": "sun1", "hOffset": 250, @@ -23,4 +23,4 @@ "alignment": "center", "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" } -}} \ No newline at end of file +}} \ No newline at end of file diff --git a/tests/inputs/test4 b/tests/inputs/test4 index d540b57f..55cd56b1 100644 --- a/tests/inputs/test4 +++ b/tests/inputs/test4 @@ -1,5 +1,5 @@ {"web-app": { - "servlet": [ + "servlet": [ { "servlet-name": "cofaxCDS", "servlet-class": "org.cofax.cds.CDSServlet", @@ -55,7 +55,7 @@ { "servlet-name": "cofaxAdmin", "servlet-class": "org.cofax.cds.AdminServlet"}, - + { "servlet-name": "fileServlet", "servlet-class": "org.cofax.cds.FileServlet"}, @@ -82,7 +82,7 @@ "cofaxAdmin": "/admin/*", "fileServlet": "/static/*", "cofaxTools": "/tools/*"}, - + "taglib": { "taglib-uri": "cofax.tld", "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} \ No newline at end of file From 27a4303f87473bc3475ff55af06de187cc8234d6 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 4 Nov 2017 14:21:51 +0100 Subject: [PATCH 077/307] Contributors: Add yangfl --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 2f858504..9353be67 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -39,5 +39,6 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB) * [Simon Ricaldone](https://github.com/simon-p-r) * [Stephan Gatzka](https://github.com/gatzka) * [Weston Schmidt](https://github.com/schmidtw) +* [yangfl](https://github.com/yangfl) And probably more people on [SourceForge](https://sourceforge.net/p/cjson/bugs/search/?q=status%3Aclosed-rejected+or+status%3Aclosed-out-of-date+or+status%3Awont-fix+or+status%3Aclosed-fixed+or+status%3Aclosed&page=0) From b2afbd3c9f38dafc0b2b8c761aa9be2b3b5f4f37 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 12 Nov 2017 14:30:26 +0100 Subject: [PATCH 078/307] cJSON_GetStringValue --- cJSON.c | 8 ++++++++ cJSON.h | 3 +++ tests/misc_tests.c | 14 ++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/cJSON.c b/cJSON.c index cef719f5..d4d2bed2 100644 --- a/cJSON.c +++ b/cJSON.c @@ -73,6 +73,14 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) return (const char*) (global_error.json + global_error.position); } +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { + if (!cJSON_IsString(item)) { + return NULL; + } + + return item->valuestring; +} + /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 6) || (CJSON_VERSION_PATCH != 0) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. diff --git a/cJSON.h b/cJSON.h index 7c4f8e7c..c8650000 100644 --- a/cJSON.h +++ b/cJSON.h @@ -165,6 +165,9 @@ CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *st /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); +/* Check if the item is a string and return its valuestring */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); + /* These functions check the type of an item */ CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 1643007e..af0cc7f9 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -450,6 +450,19 @@ static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void) TEST_ASSERT_NULL(skip_utf8_bom(&buffer)); } +static void cjson_get_string_value_should_get_a_string(void) +{ + cJSON *string = cJSON_CreateString("test"); + cJSON *number = cJSON_CreateNumber(1); + + TEST_ASSERT_TRUE(cJSON_GetStringValue(string) == string->valuestring); + TEST_ASSERT_NULL(cJSON_GetStringValue(number)); + TEST_ASSERT_NULL(cJSON_GetStringValue(NULL)); + + cJSON_Delete(number); + cJSON_Delete(string); +} + int main(void) { UNITY_BEGIN(); @@ -468,6 +481,7 @@ int main(void) RUN_TEST(ensure_should_fail_on_failed_realloc); RUN_TEST(skip_utf8_bom_should_skip_bom); RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); + RUN_TEST(cjson_get_string_value_should_get_a_string); return UNITY_END(); } From 2718d30a3df525c31454dd4dc24dd0d786a401da Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 20 Nov 2017 22:04:57 +0100 Subject: [PATCH 079/307] Squashed 'tests/json-patch-tests/' changes from 0dd0fbc..99264bb 99264bb Merge pull request #37 from FormAPI/missing_parent_key c2fae3a Added a test case to check replace op with a missing parent key git-subtree-dir: tests/json-patch-tests git-subtree-split: 99264bb634d32c03df7472f21afb7d3681d8619e --- tests.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests.json b/tests.json index 28fe4bc2..86305c16 100644 --- a/tests.json +++ b/tests.json @@ -202,6 +202,11 @@ "patch": [{"op": "replace", "path": "", "value": {"baz": "qux"}}], "expected": {"baz": "qux"} }, + { "comment": "test replace with missing parent key should fail", + "doc": {"bar": "baz"}, + "patch": [{"op": "replace", "path": "/foo/bar", "value": false}], + "error": "replace op should fail with missing parent key" }, + { "comment": "spurious patch properties", "doc": {"foo": 1}, "patch": [{"op": "test", "path": "/foo", "value": 1, "spurious": 1}], From 440390a9a59b86e066b654f95482161fbc402606 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 01:54:21 +0100 Subject: [PATCH 080/307] extract function cast_away_const_from_string --- cJSON.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index d4d2bed2..8ad32e2f 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1891,6 +1891,14 @@ CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSO #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wcast-qual" #endif +/* helper function to cast away const */ +static char* cast_away_const_from_string(const char* string) +{ + return (char*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif /* Add an item to an object with constant string as key */ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) @@ -1903,13 +1911,10 @@ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJ { global_hooks.deallocate(item->string); } - item->string = (char*)string; + item->string = cast_away_const_from_string(string); item->type |= cJSON_StringIsConst; cJSON_AddItemToArray(object, item); } -#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) - #pragma GCC diagnostic pop -#endif CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) { From eaa90a6b74494c64526cb29f54429672241b7707 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 02:02:55 +0100 Subject: [PATCH 081/307] Add cJSON_CreateStringReference --- cJSON.c | 12 ++++++++++++ cJSON.h | 4 ++++ tests/misc_tests.c | 11 +++++++++++ 3 files changed, 27 insertions(+) diff --git a/cJSON.c b/cJSON.c index 8ad32e2f..befa6a77 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2198,6 +2198,18 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) return item; } +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = cast_away_const_from_string(string); + } + + return item; +} + CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) { cJSON *item = cJSON_New_Item(&global_hooks); diff --git a/cJSON.h b/cJSON.h index c8650000..c1ba0326 100644 --- a/cJSON.h +++ b/cJSON.h @@ -192,6 +192,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); +/* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); + /* These utilities create an Array of count items. */ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index af0cc7f9..1b09a870 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -463,6 +463,16 @@ static void cjson_get_string_value_should_get_a_string(void) cJSON_Delete(string); } +static void cjson_create_string_reference_should_create_a_string_reference(void) { + const char *string = "I am a string!"; + + cJSON *string_reference = cJSON_CreateStringReference(string); + TEST_ASSERT_TRUE(string_reference->valuestring == string); + TEST_ASSERT_EQUAL_INT(cJSON_IsReference | cJSON_String, string_reference->type); + + cJSON_Delete(string_reference); +} + int main(void) { UNITY_BEGIN(); @@ -482,6 +492,7 @@ int main(void) RUN_TEST(skip_utf8_bom_should_skip_bom); RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); RUN_TEST(cjson_get_string_value_should_get_a_string); + RUN_TEST(cjson_create_string_reference_should_create_a_string_reference); return UNITY_END(); } From 1f543f0e2842f5f5af2631756d20d0cb9a410b5a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 02:05:02 +0100 Subject: [PATCH 082/307] cast_away_const: Generalize for void* --- cJSON.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index befa6a77..3d3d5d28 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1892,9 +1892,9 @@ CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSO #pragma GCC diagnostic ignored "-Wcast-qual" #endif /* helper function to cast away const */ -static char* cast_away_const_from_string(const char* string) +static void* cast_away_const(const void* string) { - return (char*)string; + return (void*)string; } #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) #pragma GCC diagnostic pop @@ -1911,7 +1911,7 @@ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJ { global_hooks.deallocate(item->string); } - item->string = cast_away_const_from_string(string); + item->string = (char*)cast_away_const(string); item->type |= cJSON_StringIsConst; cJSON_AddItemToArray(object, item); } @@ -2204,7 +2204,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) if (item != NULL) { item->type = cJSON_String | cJSON_IsReference; - item->valuestring = cast_away_const_from_string(string); + item->valuestring = (char*)cast_away_const(string); } return item; From 11844dd5a6be2e16e6107c1ab9c51b81a4910306 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 03:06:02 +0100 Subject: [PATCH 083/307] Add cJSON_Create{Array,Object}Reference --- cJSON.c | 21 +++++++++++++++++++++ cJSON.h | 4 ++++ tests/misc_tests.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/cJSON.c b/cJSON.c index 3d3d5d28..d08cb5b2 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2210,6 +2210,27 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) return item; } +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) { cJSON *item = cJSON_New_Item(&global_hooks); diff --git a/cJSON.h b/cJSON.h index c1ba0326..ba0b2587 100644 --- a/cJSON.h +++ b/cJSON.h @@ -195,6 +195,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); /* Create a string where valuestring references a string so * it will not be freed by cJSON_Delete */ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); +/* Create an object/arrray that only references it's elements so + * they will not be freed by cJSON_Delete */ +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); /* These utilities create an Array of count items. */ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 1b09a870..a900e8fc 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -473,6 +473,41 @@ static void cjson_create_string_reference_should_create_a_string_reference(void) cJSON_Delete(string_reference); } +static void cjson_create_object_reference_should_create_an_object_reference(void) { + cJSON *number_reference = NULL; + cJSON *number_object = cJSON_CreateObject(); + cJSON *number = cJSON_CreateNumber(42); + const char key[] = "number"; + + TEST_ASSERT_TRUE(cJSON_IsNumber(number)); + TEST_ASSERT_TRUE(cJSON_IsObject(number_object)); + cJSON_AddItemToObjectCS(number_object, key, number); + + number_reference = cJSON_CreateObjectReference(number); + TEST_ASSERT_TRUE(number_reference->child == number); + TEST_ASSERT_EQUAL_INT(cJSON_Object | cJSON_IsReference, number_reference->type); + + cJSON_Delete(number_object); + cJSON_Delete(number_reference); +} + +static void cjson_create_array_reference_should_create_an_array_reference(void) { + cJSON *number_reference = NULL; + cJSON *number_array = cJSON_CreateArray(); + cJSON *number = cJSON_CreateNumber(42); + + TEST_ASSERT_TRUE(cJSON_IsNumber(number)); + TEST_ASSERT_TRUE(cJSON_IsArray(number_array)); + cJSON_AddItemToArray(number_array, number); + + number_reference = cJSON_CreateArrayReference(number); + TEST_ASSERT_TRUE(number_reference->child == number); + TEST_ASSERT_EQUAL_INT(cJSON_Array | cJSON_IsReference, number_reference->type); + + cJSON_Delete(number_array); + cJSON_Delete(number_reference); +} + int main(void) { UNITY_BEGIN(); @@ -493,6 +528,8 @@ int main(void) RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); RUN_TEST(cjson_get_string_value_should_get_a_string); 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); return UNITY_END(); } From da8c48668da6e82f9cbea94e4be04d74162e71fa Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 03:15:50 +0100 Subject: [PATCH 084/307] Squashed 'tests/unity/' changes from 60b13f0..287e076 287e076 Post release 774da10 Merge pull request #296 from jlindgren90/master 629b86d Merge unity_setup.h into unity.h. 0914d80 Merge pull request #308 from codehearts/patch-1 5ee55fe Fix missing TEST_ASSERT_EACH_EQUAL_HEX_MESSAGE 38c387b Merge pull request #304 from VLambret/master 17d4ea9 Color test results using ANSI escape codes 031b1ba Merge pull request #300 from jsalling/bugfix/greater-than df78aad Make weak symbol usage more portable: a7e8797 Fix link errors with MinGW. 94a3008 Update continuous integration to build 32-bit Unity b119919 Add 64-bit comparison asserts 91bcbe1 Add 'greater/less or equal to' asserts on integers 8caade7 Fix bug in greater/less than asserts on unsigned int 1381a1a Update documentation. 2593c31 Allow suiteSetUp() and suiteTearDown() to be provided as normal C functions. 60def10 Update configuration docs git-subtree-dir: tests/unity git-subtree-split: 287e076962ec711cd2bdf08364a8df9ce51e106b --- .travis.yml | 4 +- auto/generate_test_runner.rb | 33 +++++++-- docs/UnityConfigurationGuide.md | 123 ++++++++++++++++++++----------- docs/UnityHelperScriptsGuide.md | 18 ++++- release/build.info | 2 +- release/version.info | 2 +- src/unity.c | 81 ++++++++++---------- src/unity.h | 118 ++++++++++++++++++++++++++++-- src/unity_internals.h | 126 ++++++++++++++++++++++---------- test/Makefile | 4 +- 10 files changed, 369 insertions(+), 142 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8ae9fa0c..bd165b1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,9 @@ install: script: - cd test && rake ci - make -s - - make -s DEBUG=-m32 + - make -s DEBUG=-m32 #32-bit architecture with 64-bit support + - make -s DEBUG=-m32 UNITY_SUPPORT_64= #32-bit build without 64-bit types + - make -s UNITY_INCLUDE_DOUBLE= # without double - cd ../extras/fixture/test && rake ci - make -s default noStdlibMalloc - make -s C89 diff --git a/auto/generate_test_runner.rb b/auto/generate_test_runner.rb index 07bde814..344a2d0f 100644 --- a/auto/generate_test_runner.rb +++ b/auto/generate_test_runner.rb @@ -157,6 +157,9 @@ def create_header(output, mocks, testfile_includes = []) output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */') create_runtest(output, mocks) output.puts("\n/*=======Automagically Detected Files To Include=====*/") + output.puts('#ifdef __WIN32__') + output.puts('#define UNITY_INCLUDE_SETUP_STUBS') + output.puts('#endif') output.puts("#include \"#{@options[:framework]}.h\"") output.puts('#include "cmock.h"') unless mocks.empty? output.puts('#include ') @@ -235,22 +238,36 @@ def create_mock_management(output, mock_headers) end def create_suite_setup(output) - return if @options[:suite_setup].nil? - output.puts("\n/*=======Suite Setup=====*/") output.puts('static void suite_setup(void)') output.puts('{') - output.puts(@options[:suite_setup]) + if @options[:suite_setup].nil? + # New style, call suiteSetUp() if we can use weak symbols + output.puts('#if defined(UNITY_WEAK_ATTRIBUTE) || defined(UNITY_WEAK_PRAGMA)') + output.puts(' suiteSetUp();') + output.puts('#endif') + else + # Old style, C code embedded in the :suite_setup option + output.puts(@options[:suite_setup]) + end output.puts('}') end def create_suite_teardown(output) - return if @options[:suite_teardown].nil? - output.puts("\n/*=======Suite Teardown=====*/") output.puts('static int suite_teardown(int num_failures)') output.puts('{') - output.puts(@options[:suite_teardown]) + if @options[:suite_teardown].nil? + # New style, call suiteTearDown() if we can use weak symbols + output.puts('#if defined(UNITY_WEAK_ATTRIBUTE) || defined(UNITY_WEAK_PRAGMA)') + output.puts(' return suiteTearDown(num_failures);') + output.puts('#else') + output.puts(' return num_failures;') + output.puts('#endif') + else + # Old style, C code embedded in the :suite_teardown option + output.puts(@options[:suite_teardown]) + end output.puts('}') end @@ -342,7 +359,7 @@ def create_main(output, filename, tests, used_mocks) output.puts("int #{main_name}(void)") output.puts('{') end - output.puts(' suite_setup();') unless @options[:suite_setup].nil? + output.puts(' suite_setup();') output.puts(" UnityBegin(\"#{filename.gsub(/\\/, '\\\\\\')}\");") if @options[:use_param_tests] tests.each do |test| @@ -357,7 +374,7 @@ def create_main(output, filename, tests, used_mocks) end output.puts output.puts(' CMock_Guts_MemFreeFinal();') unless used_mocks.empty? - output.puts(" return #{@options[:suite_teardown].nil? ? '' : 'suite_teardown'}(UnityEnd());") + output.puts(" return suite_teardown(UnityEnd());") output.puts('}') end diff --git a/docs/UnityConfigurationGuide.md b/docs/UnityConfigurationGuide.md index 283d7799..96e5358d 100644 --- a/docs/UnityConfigurationGuide.md +++ b/docs/UnityConfigurationGuide.md @@ -79,18 +79,7 @@ _Example:_ #define UNITY_EXCLUDE_LIMITS_H -##### `UNITY_EXCLUDE_SIZEOF` - -The third and final attempt to guess your types is to use the `sizeof()` -operator. Even if the first two options don't work, this one covers most cases. -There _is_ a rare compiler or two out there that doesn't support sizeof() in the -preprocessing stage, though. For these, you have the ability to disable this -feature as well. - -_Example:_ - #define UNITY_EXCLUDE_SIZEOF - -If you've disabled all of the automatic options above, you're going to have to +If you've disabled both of the automatic options above, you're going to have to do the configuration yourself. Don't worry. Even this isn't too bad... there are just a handful of defines that you are going to specify if you don't like the defaults. @@ -127,7 +116,7 @@ _Example:_ #define UNITY_POINTER_WIDTH 64 -##### `UNITY_INCLUDE_64` +##### `UNITY_SUPPORT_64` Unity will automatically include 64-bit support if it auto-detects it, or if your `int`, `long`, or pointer widths are greater than 32-bits. Define this to @@ -136,7 +125,7 @@ can be a significant size and speed impact to enabling 64-bit support on small targets, so don't define it if you don't need it. _Example:_ - #define UNITY_INCLUDE_64 + #define UNITY_SUPPORT_64 ### Floating Point Types @@ -170,24 +159,20 @@ _Example:_ #define UNITY_INCLUDE_DOUBLE -##### `UNITY_FLOAT_VERBOSE` - -##### `UNITY_DOUBLE_VERBOSE` +##### `UNITY_EXCLUDE_FLOAT_PRINT` Unity aims for as small of a footprint as possible and avoids most standard -library calls (some embedded platforms don't have a standard library!). Because +library calls (some embedded platforms don’t have a standard library!). Because of this, its routines for printing integer values are minimalist and hand-coded. -To keep Unity universal, though, we chose to _not_ develop our own floating -point print routines. Instead, the display of floating point values during a -failure are optional. By default, Unity will not print the actual results of -floating point assertion failure. So a failed assertion will produce a message -like `"Values Not Within Delta"`. If you would like verbose failure messages for -floating point assertions, use these options to give more explicit failure -messages (e.g. `"Expected 4.56 Was 4.68"`). Note that this feature requires the -use of `sprintf` so might not be desirable in all cases. +Therefore, the display of floating point values during a failure are optional. +By default, Unity will print the actual results of floating point assertion +failure (e.g. ”Expected 4.56 Was 4.68”). To not include this extra support, you +can use this define to instead respond to a failed assertion with a message like +”Values Not Within Delta”. If you would like verbose failure messages for floating +point assertions, use these options to give more explicit failure messages. _Example:_ - #define UNITY_DOUBLE_VERBOSE + #define UNITY_EXCLUDE_FLOAT_PRINT ##### `UNITY_FLOAT_TYPE` @@ -277,25 +262,32 @@ will declare an instance of your function by default. If you want to disable this behavior, add `UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION`. -##### `UNITY_SUPPORT_WEAK` +##### `UNITY_WEAK_ATTRIBUTE` + +##### `UNITY_WEAK_PRAGMA` + +##### `UNITY_NO_WEAK` -For some targets, Unity can make the otherwise required `setUp()` and -`tearDown()` functions optional. This is a nice convenience for test writers -since `setUp` and `tearDown` don't often actually _do_ anything. If you're using -gcc or clang, this option is automatically defined for you. Other compilers can -also support this behavior, if they support a C feature called weak functions. A -weak function is a function that is compiled into your executable _unless_ a -non-weak version of the same function is defined elsewhere. If a non-weak -version is found, the weak version is ignored as if it never existed. If your -compiler supports this feature, you can let Unity know by defining -`UNITY_SUPPORT_WEAK` as the function attributes that would need to be applied to -identify a function as weak. If your compiler lacks support for weak functions, -you will always need to define `setUp` and `tearDown` functions (though they can -be and often will be just empty). The most common options for this feature are: +For some targets, Unity can make the otherwise required setUp() and tearDown() +functions optional. This is a nice convenience for test writers since setUp and +tearDown don’t often actually do anything. If you’re using gcc or clang, this +option is automatically defined for you. Other compilers can also support this +behavior, if they support a C feature called weak functions. A weak function is +a function that is compiled into your executable unless a non-weak version of +the same function is defined elsewhere. If a non-weak version is found, the weak +version is ignored as if it never existed. If your compiler supports this feature, +you can let Unity know by defining UNITY_WEAK_ATTRIBUTE or UNITY_WEAK_PRAGMA as +the function attributes that would need to be applied to identify a function as +weak. If your compiler lacks support for weak functions, you will always need to +define setUp and tearDown functions (though they can be and often will be just +empty). You can also force Unity to NOT use weak functions by defining +UNITY_NO_WEAK. The most common options for this feature are: _Example:_ - #define UNITY_SUPPORT_WEAK weak - #define UNITY_SUPPORT_WEAK __attribute__((weak)) + #define UNITY_WEAK_ATTRIBUTE weak + #define UNITY_WEAK_ATTRIBUTE __attribute__((weak)) + #define UNITY_WEAK_PRAGMA + #define UNITY_NO_WEAK ##### `UNITY_PTR_ATTRIBUTE` @@ -309,6 +301,51 @@ _Example:_ #define UNITY_PTR_ATTRIBUTE near +##### `UNITY_PRINT_EOL` + +By default, Unity outputs \n at the end of each line of output. This is easy +to parse by the scripts, by Ceedling, etc, but it might not be ideal for YOUR +system. Feel free to override this and to make it whatever you wish. + +_Example:_ + #define UNITY_PRINT_EOL { UNITY_OUTPUT_CHAR('\r'); UNITY_OUTPUT_CHAR('\n') } + + + +##### `UNITY_EXCLUDE_DETAILS` + +This is an option for if you absolutely must squeeze every byte of memory out of +your system. Unity stores a set of internal scratchpads which are used to pass +extra detail information around. It's used by systems like CMock in order to +report which function or argument flagged an error. If you're not using CMock and +you're not using these details for other things, then you can exclude them. + +_Example:_ + #define UNITY_EXCLUDE_DETAILS + + + +##### `UNITY_EXCLUDE_SETJMP` + +If your embedded system doesn't support the standard library setjmp, you can +exclude Unity's reliance on this by using this define. This dropped dependence +comes at a price, though. You will be unable to use custom helper functions for +your tests, and you will be unable to use tools like CMock. Very likely, if your +compiler doesn't support setjmp, you wouldn't have had the memory space for those +things anyway, though... so this option exists for those situations. + +_Example:_ + #define UNITY_EXCLUDE_SETJMP + +##### `UNITY_OUTPUT_COLOR` + +If you want to add color using ANSI escape codes you can use this define. +t +_Example:_ + #define UNITY_OUTPUT_COLOR + + + ## Getting Into The Guts There will be cases where the options above aren't quite going to get everything diff --git a/docs/UnityHelperScriptsGuide.md b/docs/UnityHelperScriptsGuide.md index 3a930096..42429900 100644 --- a/docs/UnityHelperScriptsGuide.md +++ b/docs/UnityHelperScriptsGuide.md @@ -124,7 +124,7 @@ demonstrates using a Ruby hash. ##### `:includes` -This option specifies an array of file names to be ?#include?'d at the top of +This option specifies an array of file names to be `#include`'d at the top of your runner C file. You might use it to reference custom types or anything else universally needed in your generated runners. @@ -133,11 +133,23 @@ universally needed in your generated runners. Define this option with C code to be executed _before any_ test cases are run. +Alternatively, if your C compiler supports weak symbols, you can leave this +option unset and instead provide a `void suiteSetUp(void)` function in your test +suite. The linker will look for this symbol and fall back to a Unity-provided +stub if it is not found. + ##### `:suite_teardown` -Define this option with C code to be executed ?after all?test cases have -finished. +Define this option with C code to be executed _after all_ test cases have +finished. An integer variable `num_failures` is available for diagnostics. +The code should end with a `return` statement; the value returned will become +the exit code of `main`. You can normally just return `num_failures`. + +Alternatively, if your C compiler supports weak symbols, you can leave this +option unset and instead provide a `int suiteTearDown(int num_failures)` +function in your test suite. The linker will look for this symbol and fall +back to a Unity-provided stub if it is not found. ##### `:enforce_strict_ordering` diff --git a/release/build.info b/release/build.info index 50fb6eaf..56d59128 100644 --- a/release/build.info +++ b/release/build.info @@ -1,2 +1,2 @@ -121 +122 diff --git a/release/version.info b/release/version.info index b674b923..cf12b30d 100644 --- a/release/version.info +++ b/release/version.info @@ -1,2 +1,2 @@ -2.4.2 +2.4.3 diff --git a/src/unity.c b/src/unity.c index 9783efac..0f2d2dea 100644 --- a/src/unity.c +++ b/src/unity.c @@ -4,6 +4,7 @@ [Released under MIT License. Please refer to license.txt for details] ============================================================================ */ +#define UNITY_INCLUDE_SETUP_STUBS #include "unity.h" #include @@ -19,16 +20,24 @@ void UNITY_OUTPUT_CHAR(int); struct UNITY_STORAGE_T Unity; +#ifdef UNITY_OUTPUT_COLOR +static const char UnityStrOk[] = "\033[42mOK\033[00m"; +static const char UnityStrPass[] = "\033[42mPASS\033[00m"; +static const char UnityStrFail[] = "\033[41mFAIL\033[00m"; +static const char UnityStrIgnore[] = "\033[43mIGNORE\033[00m"; +#else static const char UnityStrOk[] = "OK"; static const char UnityStrPass[] = "PASS"; static const char UnityStrFail[] = "FAIL"; static const char UnityStrIgnore[] = "IGNORE"; +#endif static const char UnityStrNull[] = "NULL"; static const char UnityStrSpacer[] = ". "; static const char UnityStrExpected[] = " Expected "; static const char UnityStrWas[] = " Was "; static const char UnityStrGt[] = " to be greater than "; static const char UnityStrLt[] = " to be less than "; +static const char UnityStrOrEqual[] = "or equal to "; static const char UnityStrElement[] = " Element "; static const char UnityStrByte[] = " Byte "; static const char UnityStrMemory[] = " Memory Mismatch."; @@ -83,6 +92,18 @@ void UnityPrint(const char* string) UNITY_OUTPUT_CHAR('\\'); UNITY_OUTPUT_CHAR('n'); } +#ifdef UNITY_OUTPUT_COLOR + /* print ANSI escape code */ + else if (*pch == 27 && *(pch + 1) == '[') + { + while (*pch && *pch != 'm') + { + UNITY_OUTPUT_CHAR(*pch); + pch++; + } + UNITY_OUTPUT_CHAR('m'); + } +#endif /* unprintable characters are shown as codes */ else { @@ -531,49 +552,44 @@ void UnityAssertEqualNumber(const UNITY_INT expected, } /*-----------------------------------------------*/ -void UnityAssertGreaterNumber(const UNITY_INT threshold, - const UNITY_INT actual, - const char *msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style) +void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const UNITY_COMPARISON_T compare, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) { + int failed = 0; RETURN_IF_FAIL_OR_IGNORE; - if (!(actual > threshold)) + if (threshold == actual && compare & UNITY_EQUAL_TO) return; + if (threshold == actual) failed = 1; + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) { - UnityTestResultsFailBegin(lineNumber); - UnityPrint(UnityStrExpected); - UnityPrintNumberByStyle(actual, style); - UnityPrint(UnityStrGt); - UnityPrintNumberByStyle(threshold, style); - UnityAddMsgIfSpecified(msg); - UNITY_FAIL_AND_BAIL; + if (actual > threshold && compare & UNITY_SMALLER_THAN) failed = 1; + if (actual < threshold && compare & UNITY_GREATER_THAN) failed = 1; + } + else /* UINT or HEX */ + { + if ((UNITY_UINT)actual > (UNITY_UINT)threshold && compare & UNITY_SMALLER_THAN) failed = 1; + if ((UNITY_UINT)actual < (UNITY_UINT)threshold && compare & UNITY_GREATER_THAN) failed = 1; } -} - -/*-----------------------------------------------*/ -void UnityAssertSmallerNumber(const UNITY_INT threshold, - const UNITY_INT actual, - const char *msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style) -{ - RETURN_IF_FAIL_OR_IGNORE; - if (!(actual < threshold)) + if (failed) { UnityTestResultsFailBegin(lineNumber); UnityPrint(UnityStrExpected); UnityPrintNumberByStyle(actual, style); - UnityPrint(UnityStrLt); + if (compare & UNITY_GREATER_THAN) UnityPrint(UnityStrGt); + if (compare & UNITY_SMALLER_THAN) UnityPrint(UnityStrLt); + if (compare & UNITY_EQUAL_TO) UnityPrint(UnityStrOrEqual); UnityPrintNumberByStyle(threshold, style); UnityAddMsgIfSpecified(msg); UNITY_FAIL_AND_BAIL; } } - - #define UnityPrintPointlessAndBail() \ { \ UnityTestResultsFailBegin(lineNumber); \ @@ -1310,17 +1326,6 @@ void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line) UNITY_IGNORE_AND_BAIL; } -/*-----------------------------------------------*/ -#if defined(UNITY_WEAK_ATTRIBUTE) - UNITY_WEAK_ATTRIBUTE void setUp(void) { } - UNITY_WEAK_ATTRIBUTE void tearDown(void) { } -#elif defined(UNITY_WEAK_PRAGMA) - #pragma weak setUp - void setUp(void) { } - #pragma weak tearDown - void tearDown(void) { } -#endif - /*-----------------------------------------------*/ void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum) { diff --git a/src/unity.h b/src/unity.h index 258e21c9..32ff0e6d 100644 --- a/src/unity.h +++ b/src/unity.h @@ -15,9 +15,43 @@ extern "C" #include "unity_internals.h" +/*------------------------------------------------------- + * Test Setup / Teardown + *-------------------------------------------------------*/ + +/* These functions are intended to be called before and after each test. */ void setUp(void); void tearDown(void); +/* These functions are intended to be called at the beginning and end of an + * entire test suite. suiteTearDown() is passed the number of tests that + * failed, and its return value becomes the exit code of main(). */ +void suiteSetUp(void); +int suiteTearDown(int num_failures); + +/* If the compiler supports it, the following block provides stub + * implementations of the above functions as weak symbols. Note that on + * some platforms (MinGW for example), weak function implementations need + * to be in the same translation unit they are called from. This can be + * achieved by defining UNITY_INCLUDE_SETUP_STUBS before including unity.h. */ +#ifdef UNITY_INCLUDE_SETUP_STUBS + #ifdef UNITY_WEAK_ATTRIBUTE + UNITY_WEAK_ATTRIBUTE void setUp(void) { } + UNITY_WEAK_ATTRIBUTE void tearDown(void) { } + UNITY_WEAK_ATTRIBUTE void suiteSetUp(void) { } + UNITY_WEAK_ATTRIBUTE int suiteTearDown(int num_failures) { return num_failures; } + #elif defined(UNITY_WEAK_PRAGMA) + #pragma weak setUp + void setUp(void) { } + #pragma weak tearDown + void tearDown(void) { } + #pragma weak suiteSetUp + void suiteSetUp(void) { } + #pragma weak suiteTearDown + int suiteTearDown(int num_failures) { return num_failures; } + #endif +#endif + /*------------------------------------------------------- * Configuration Options *------------------------------------------------------- @@ -120,28 +154,64 @@ void tearDown(void); #define TEST_ASSERT_GREATER_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, NULL) - +#define TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_THAN_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, NULL) #define TEST_ASSERT_LESS_THAN_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, NULL) - +#define TEST_ASSERT_LESS_THAN_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_GREATER_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) + +#define TEST_ASSERT_LESS_OR_EQUAL(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_INT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX8(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX16(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX32(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, NULL) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX64(threshold, actual) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, NULL) /* Integer Ranges (of all sizes) */ #define TEST_ASSERT_INT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, NULL) @@ -186,8 +256,6 @@ void tearDown(void); #define TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY((expected), (actual), (len), (num_elements), __LINE__, NULL) - - /* Arrays Compared To Single Value */ #define TEST_ASSERT_EACH_EQUAL_INT(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT((expected), (actual), (num_elements), __LINE__, NULL) #define TEST_ASSERT_EACH_EQUAL_INT8(expected, actual, num_elements) UNITY_TEST_ASSERT_EACH_EQUAL_INT8((expected), (actual), (num_elements), __LINE__, NULL) @@ -278,28 +346,64 @@ void tearDown(void); #define TEST_ASSERT_GREATER_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT8((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT16((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_INT64((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT8((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT16((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_UINT64((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX8((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX16((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_GREATER_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX32((threshold), (actual), __LINE__, (message)) - +#define TEST_ASSERT_GREATER_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_THAN_HEX64((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT8((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT16((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_INT64((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT8((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT16((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_THAN_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_UINT64((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX8((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX16((threshold), (actual), __LINE__, (message)) #define TEST_ASSERT_LESS_THAN_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, (message)) - +#define TEST_ASSERT_LESS_THAN_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_GREATER_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64((threshold), (actual), __LINE__, (message)) + +#define TEST_ASSERT_LESS_OR_EQUAL_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_INT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_UINT64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX8_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX16_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX32_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX32((threshold), (actual), __LINE__, (message)) +#define TEST_ASSERT_LESS_OR_EQUAL_HEX64_MESSAGE(threshold, actual, message) UNITY_TEST_ASSERT_SMALLER_THAN_HEX64((threshold), (actual), __LINE__, (message)) /* Integer Ranges (of all sizes) */ #define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT_WITHIN((delta), (expected), (actual), __LINE__, (message)) @@ -355,7 +459,7 @@ void tearDown(void); #define TEST_ASSERT_EACH_EQUAL_UINT16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT16((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_UINT32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT32((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_UINT64_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_UINT64((expected), (actual), (num_elements), __LINE__, (message)) -#define TEST_ASSERT_EACH_EQUAL_HEX32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) +#define TEST_ASSERT_EACH_EQUAL_HEX_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_HEX8_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX8((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_HEX16_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX16((expected), (actual), (num_elements), __LINE__, (message)) #define TEST_ASSERT_EACH_EQUAL_HEX32_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EACH_EQUAL_HEX32((expected), (actual), (num_elements), __LINE__, (message)) diff --git a/src/unity_internals.h b/src/unity_internals.h index 1b57cd02..67e219b8 100644 --- a/src/unity_internals.h +++ b/src/unity_internals.h @@ -301,7 +301,7 @@ extern void UNITY_OMIT_OUTPUT_FLUSH_HEADER_DECLARATION; * Language Features Available *-------------------------------------------------------*/ #if !defined(UNITY_WEAK_ATTRIBUTE) && !defined(UNITY_WEAK_PRAGMA) -# ifdef __GNUC__ /* includes clang */ +# if defined(__GNUC__) || defined(__ghs__) /* __GNUC__ includes clang */ # if !(defined(__WIN32__) && defined(__clang__)) && !defined(__TMS470__) # define UNITY_WEAK_ATTRIBUTE __attribute__((weak)) # endif @@ -352,6 +352,15 @@ UNITY_DISPLAY_STYLE_UINT = sizeof(unsigned) + UNITY_DISPLAY_RANGE_UINT, UNITY_DISPLAY_STYLE_UNKNOWN } UNITY_DISPLAY_STYLE_T; +typedef enum +{ + UNITY_EQUAL_TO = 1, + UNITY_GREATER_THAN = 2, + UNITY_GREATER_OR_EQUAL = 2 + UNITY_EQUAL_TO, + UNITY_SMALLER_THAN = 4, + UNITY_SMALLER_OR_EQUAL = 4 + UNITY_EQUAL_TO +} UNITY_COMPARISON_T; + #ifndef UNITY_EXCLUDE_FLOAT typedef enum UNITY_FLOAT_TRAIT { @@ -455,17 +464,12 @@ void UnityAssertEqualNumber(const UNITY_INT expected, const UNITY_LINE_TYPE lineNumber, const UNITY_DISPLAY_STYLE_T style); -void UnityAssertGreaterNumber(const UNITY_INT threshold, - const UNITY_INT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style); - -void UnityAssertSmallerNumber(const UNITY_INT threshold, - const UNITY_INT actual, - const char* msg, - const UNITY_LINE_TYPE lineNumber, - const UNITY_DISPLAY_STYLE_T style); +void UnityAssertGreaterOrLessOrEqualNumber(const UNITY_INT threshold, + const UNITY_INT actual, + const UNITY_COMPARISON_T compare, + const char *msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); void UnityAssertEqualIntArray(UNITY_INTERNAL_PTR expected, UNITY_INTERNAL_PTR actual, @@ -664,33 +668,53 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message) UnityAssertEqualNumber((UNITY_INT)(UNITY_INT32)(expected), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) #define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((UNITY_INT)(mask), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line)) - -#define UNITY_TEST_ASSERT_GREATER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_GREATER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_GREATER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_GREATER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) - - -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT8(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT16(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) -#define UNITY_TEST_ASSERT_SMALLER_THAN_INT32(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT8(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT16(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) -#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT32(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) -#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX8(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) -#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX16(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) -#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX32(threshold, actual, line, message) UnityAssertSmallerNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) - - +#define UNITY_TEST_ASSERT_GREATER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) + +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) + +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) + +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT8 )(threshold), (UNITY_INT)(UNITY_INT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT16)(threshold), (UNITY_INT)(UNITY_INT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_INT32)(threshold), (UNITY_INT)(UNITY_INT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX8(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT8 )(threshold), (UNITY_INT)(UNITY_UINT8 )(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX16(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT16)(threshold), (UNITY_INT)(UNITY_UINT16)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX32(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(UNITY_UINT32)(threshold), (UNITY_INT)(UNITY_UINT32)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX32) #define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT) #define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((UNITY_UINT8 )(delta), (UNITY_INT)(UNITY_INT8 )(expected), (UNITY_INT)(UNITY_INT8 )(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT8) @@ -752,6 +776,18 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) #define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) #define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((delta), (UNITY_INT)(expected), (UNITY_INT)(actual), (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_GREATER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_THAN, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UnityAssertGreaterOrLessOrEqualNumber((UNITY_INT)(threshold), (UNITY_INT)(actual), UNITY_SMALLER_OR_EQUAL, (message), (UNITY_LINE_TYPE)(line), UNITY_DISPLAY_STYLE_HEX64) #else #define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) #define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) @@ -762,6 +798,18 @@ int UnityTestMatches(void); #define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) #define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) #define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_GREATER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_THAN_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_INT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_UINT64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) +#define UNITY_TEST_ASSERT_SMALLER_OR_EQUAL_HEX64(threshold, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)(line), UnityStrErr64) #endif #ifdef UNITY_EXCLUDE_FLOAT diff --git a/test/Makefile b/test/Makefile index 9de7a49a..c2710f1f 100644 --- a/test/Makefile +++ b/test/Makefile @@ -15,7 +15,9 @@ CFLAGS += -Wbad-function-cast -Wcast-qual -Wold-style-definition -Wshadow -Wstri CFLAGS += $(DEBUG) DEFINES = -D UNITY_OUTPUT_CHAR=putcharSpy DEFINES += -D UNITY_OUTPUT_CHAR_HEADER_DECLARATION=putcharSpy\(int\) -DEFINES += -D UNITY_SUPPORT_64 -D UNITY_INCLUDE_DOUBLE +DEFINES += $(UNITY_SUPPORT_64) $(UNITY_INCLUDE_DOUBLE) +UNITY_SUPPORT_64 = -D UNITY_SUPPORT_64 +UNITY_INCLUDE_DOUBLE = -D UNITY_INCLUDE_DOUBLE SRC = ../src/unity.c tests/testunity.c build/testunityRunner.c INC_DIR = -I ../src COV_FLAGS = -fprofile-arcs -ftest-coverage -I ../../src From eb7c681a4b363c1ca7eebc5d1259e89283866ffb Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 16:44:24 +0100 Subject: [PATCH 085/307] Fix tests when building as static library --- tests/CMakeLists.txt | 6 +-- tests/common.c | 97 -------------------------------------------- tests/common.h | 75 +++++++++++++++++++++++++++++++++- 3 files changed, 75 insertions(+), 103 deletions(-) delete mode 100644 tests/common.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f7c1779c..e63c500d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -57,8 +57,6 @@ if(ENABLE_CJSON_TEST) compare_tests ) - add_library(test-common common.c) - option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.") if (ENABLE_VALGRIND) find_program(MEMORYCHECK_COMMAND valgrind) @@ -72,7 +70,7 @@ if(ENABLE_CJSON_TEST) foreach(unity_test ${unity_tests}) add_executable("${unity_test}" "${unity_test}.c") - target_link_libraries("${unity_test}" "${CJSON_LIB}" unity test-common) + target_link_libraries("${unity_test}" "${CJSON_LIB}" unity) if(MEMORYCHECK_COMMAND) add_test(NAME "${unity_test}" COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "${CMAKE_CURRENT_BINARY_DIR}/${unity_test}") @@ -97,7 +95,7 @@ if(ENABLE_CJSON_TEST) foreach (cjson_utils_test ${cjson_utils_tests}) add_executable("${cjson_utils_test}" "${cjson_utils_test}.c") - target_link_libraries("${cjson_utils_test}" "${CJSON_LIB}" "${CJSON_UTILS_LIB}" unity test-common) + target_link_libraries("${cjson_utils_test}" "${CJSON_LIB}" "${CJSON_UTILS_LIB}" unity) if(MEMORYCHECK_COMMAND) add_test(NAME "${cjson_utils_test}" COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "${CMAKE_CURRENT_BINARY_DIR}/${cjson_utils_test}") diff --git a/tests/common.c b/tests/common.c deleted file mode 100644 index 12022e11..00000000 --- a/tests/common.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -#include "common.h" - -CJSON_PUBLIC(void) reset(cJSON *item) -{ - if ((item != NULL) && (item->child != NULL)) - { - cJSON_Delete(item->child); - } - if ((item->valuestring != NULL) && !(item->type & cJSON_IsReference)) - { - global_hooks.deallocate(item->valuestring); - } - if ((item->string != NULL) && !(item->type & cJSON_StringIsConst)) - { - global_hooks.deallocate(item->string); - } - - memset(item, 0, sizeof(cJSON)); -} - -CJSON_PUBLIC(char*) read_file(const char *filename) -{ - FILE *file = NULL; - long length = 0; - char *content = NULL; - size_t read_chars = 0; - - /* open in read binary mode */ - file = fopen(filename, "rb"); - if (file == NULL) - { - goto cleanup; - } - - /* get the length */ - if (fseek(file, 0, SEEK_END) != 0) - { - goto cleanup; - } - length = ftell(file); - if (length < 0) - { - goto cleanup; - } - if (fseek(file, 0, SEEK_SET) != 0) - { - goto cleanup; - } - - /* allocate content buffer */ - content = (char*)malloc((size_t)length + sizeof("")); - if (content == NULL) - { - goto cleanup; - } - - /* read the file into memory */ - read_chars = fread(content, sizeof(char), (size_t)length, file); - if ((long)read_chars != length) - { - free(content); - content = NULL; - goto cleanup; - } - content[read_chars] = '\0'; - - -cleanup: - if (file != NULL) - { - fclose(file); - } - - return content; -} diff --git a/tests/common.h b/tests/common.h index 97c09bf2..4db6bf8c 100644 --- a/tests/common.h +++ b/tests/common.h @@ -25,8 +25,79 @@ #include "../cJSON.c" -CJSON_PUBLIC(void) reset(cJSON *item); -CJSON_PUBLIC(char*) read_file(const char *filename); +void reset(cJSON *item); +void reset(cJSON *item) { + if ((item != NULL) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if ((item->valuestring != NULL) && !(item->type & cJSON_IsReference)) + { + global_hooks.deallocate(item->valuestring); + } + if ((item->string != NULL) && !(item->type & cJSON_StringIsConst)) + { + global_hooks.deallocate(item->string); + } + + memset(item, 0, sizeof(cJSON)); +} + +char* read_file(const char *filename); +char* read_file(const char *filename) { + FILE *file = NULL; + long length = 0; + char *content = NULL; + size_t read_chars = 0; + + /* open in read binary mode */ + file = fopen(filename, "rb"); + if (file == NULL) + { + goto cleanup; + } + + /* get the length */ + if (fseek(file, 0, SEEK_END) != 0) + { + goto cleanup; + } + length = ftell(file); + if (length < 0) + { + goto cleanup; + } + if (fseek(file, 0, SEEK_SET) != 0) + { + goto cleanup; + } + + /* allocate content buffer */ + content = (char*)malloc((size_t)length + sizeof("")); + if (content == NULL) + { + goto cleanup; + } + + /* read the file into memory */ + read_chars = fread(content, sizeof(char), (size_t)length, file); + if ((long)read_chars != length) + { + free(content); + content = NULL; + goto cleanup; + } + content[read_chars] = '\0'; + + +cleanup: + if (file != NULL) + { + fclose(file); + } + + return content; +} /* assertion helper macros */ #define assert_has_type(item, item_type) TEST_ASSERT_BITS_MESSAGE(0xFF, item_type, item->type, "Item doesn't have expected type.") From 2a087843e4f8b6bfae57d35621e3787e0b999a21 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 28 Nov 2017 17:16:11 +0100 Subject: [PATCH 086/307] Add overrides for BUILD_SHARED_LIBS --- CMakeLists.txt | 13 +++++++++++-- README.md | 1 + tests/CMakeLists.txt | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 24132562..97f9cfe6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,9 +123,18 @@ file(GLOB HEADERS cJSON.h) set(SOURCES cJSON.c) option(BUILD_SHARED_AND_STATIC_LIBS "Build both shared and static libraries" Off) +option(CJSON_OVERRIDE_BUILD_SHARED_LIBS "Override BUILD_SHARED_LIBS with CJSON_BUILD_SHARED_LIBS" OFF) +option(CJSON_BUILD_SHARED_LIBS "Overrides BUILD_SHARED_LIBS if CJSON_OVERRIDE_BUILD_SHARED_LIBS is enabled" ON) + +if ((CJSON_OVERRIDE_BUILD_SHARED_LIBS AND CJSON_BUILD_SHARED_LIBS) OR ((NOT CJSON_OVERRIDE_BUILD_SHARED_LIBS) AND BUILD_SHARED_LIBS)) + set(CJSON_LIBRARY_TYPE SHARED) +else() + set(CJSON_LIBRARY_TYPE STATIC) +endif() + if (NOT BUILD_SHARED_AND_STATIC_LIBS) - add_library("${CJSON_LIB}" "${HEADERS}" "${SOURCES}") + add_library("${CJSON_LIB}" "${CJSON_LIBRARY_TYPE}" "${HEADERS}" "${SOURCES}") else() # See https://cmake.org/Wiki/CMake_FAQ#How_do_I_make_my_shared_and_static_libraries_have_the_same_root_name.2C_but_different_suffixes.3F add_library("${CJSON_LIB}" SHARED "${HEADERS}" "${SOURCES}") @@ -165,7 +174,7 @@ if(ENABLE_CJSON_UTILS) set(SOURCES_UTILS cJSON_Utils.c) if (NOT BUILD_SHARED_AND_STATIC_LIBS) - add_library("${CJSON_UTILS_LIB}" "${HEADERS_UTILS}" "${SOURCES_UTILS}") + add_library("${CJSON_UTILS_LIB}" "${CJSON_LIBRARY_TYPE}" "${HEADERS_UTILS}" "${SOURCES_UTILS}") target_link_libraries("${CJSON_UTILS_LIB}" "${CJSON_LIB}") else() add_library("${CJSON_UTILS_LIB}" SHARED "${HEADERS_UTILS}" "${SOURCES_UTILS}") diff --git a/README.md b/README.md index ddfea3f4..82245cba 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ You can change the build process with a list of different options that you can p * `-DBUILD_SHARED_AND_STATIC_LIBS=On`: Build both shared and static libraries. (off by default) * `-DCMAKE_INSTALL_PREFIX=/usr`: Set a prefix for the installation. * `-DENABLE_LOCALES=On`: Enable the usage of localeconv method. ( on by default ) +* `-DCJSON_OVERRIDE_BUILD_SHARED_LIBS=On`: Enable overriding the value of `BUILD_SHARED_LIBS` with `-DCJSON_BUILD_SHARED_LIBS`. If you are packaging cJSON for a distribution of Linux, you would probably take these steps for example: ``` diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e63c500d..f8b121c7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,5 @@ if(ENABLE_CJSON_TEST) - add_library(unity unity/src/unity.c) + add_library(unity "${CJSON_LIBRARY_TYPE}" unity/src/unity.c) # Disable -Werror for Unity if (FLAG_SUPPORTED_Werror) From 55c597c719fcadb7e4963c2b9f819e0e0e00a699 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 28 Dec 2017 12:45:28 +0100 Subject: [PATCH 087/307] add_item_to_array with boolean return value --- cJSON.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/cJSON.c b/cJSON.c index d08cb5b2..98f70814 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1844,14 +1844,13 @@ static cJSON *create_reference(const cJSON *item, const internal_hooks * const h return reference; } -/* Add item to array/object. */ -CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) { cJSON *child = NULL; if ((item == NULL) || (array == NULL)) { - return; + return false; } child = array->child; @@ -1870,6 +1869,14 @@ CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) } suffix_object(child, item); } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + add_item_to_array(array, item); } CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) @@ -1913,7 +1920,7 @@ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJ } item->string = (char*)cast_away_const(string); item->type |= cJSON_StringIsConst; - cJSON_AddItemToArray(object, item); + add_item_to_array(object, item); } CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) @@ -1923,7 +1930,7 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) return; } - cJSON_AddItemToArray(array, create_reference(item, &global_hooks)); + add_item_to_array(array, create_reference(item, &global_hooks)); } CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) @@ -2018,7 +2025,7 @@ CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newit after_inserted = get_array_item(array, (size_t)which); if (after_inserted == NULL) { - cJSON_AddItemToArray(array, newitem); + add_item_to_array(array, newitem); return; } From de729a1635503af70b7b285dc167503c34b5be06 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 28 Dec 2017 17:19:03 +0100 Subject: [PATCH 088/307] Extract add_item_to_object function that returns a boolean --- cJSON.c | 61 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/cJSON.c b/cJSON.c index 98f70814..79ce826d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1879,19 +1879,6 @@ CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) add_item_to_array(array, item); } -CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) -{ - if (item == NULL) - { - return; - } - - /* call cJSON_AddItemToObjectCS for code reuse */ - cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item); - /* remove cJSON_StringIsConst flag */ - item->type &= ~cJSON_StringIsConst; -} - #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) #pragma GCC diagnostic push #endif @@ -1907,20 +1894,48 @@ static void* cast_away_const(const void* string) #pragma GCC diagnostic pop #endif -/* Add an item to an object with constant string as key */ -CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) + +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) { - if ((item == NULL) || (string == NULL)) + if ((object == NULL) || (string == NULL) || (item == NULL)) { - return; + return false; } - if (!(item->type & cJSON_StringIsConst) && item->string) + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + if (constant_key) { - global_hooks.deallocate(item->string); + item->string = (char*)cast_away_const(string); + item->type |= cJSON_StringIsConst; } - item->string = (char*)cast_away_const(string); - item->type |= cJSON_StringIsConst; - add_item_to_array(object, item); + else + { + char *key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (key == NULL) + { + return false; + } + + item->string = key; + item->type &= ~cJSON_StringIsConst; + } + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, true); } CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) @@ -1940,7 +1955,7 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *str return; } - cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks)); + add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); } CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) From f966409b33ef07bcc6beb2416eeaee4181b622e1 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 28 Dec 2017 22:56:57 +0100 Subject: [PATCH 089/307] Add tests for cJSON_Add...ToObject macros --- tests/CMakeLists.txt | 1 + tests/cjson_add.c | 145 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 tests/cjson_add.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f8b121c7..01496f87 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -55,6 +55,7 @@ if(ENABLE_CJSON_TEST) misc_tests parse_with_opts compare_tests + cjson_add ) option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.") diff --git a/tests/cjson_add.c b/tests/cjson_add.c new file mode 100644 index 00000000..601d6664 --- /dev/null +++ b/tests/cjson_add.c @@ -0,0 +1,145 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include +#include + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" + +static void cjson_add_null_should_add_null(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *null = NULL; + + cJSON_AddNullToObject(root, "null"); + + TEST_ASSERT_NOT_NULL(null = cJSON_GetObjectItemCaseSensitive(root, "null")); + TEST_ASSERT_EQUAL_INT(null->type, cJSON_NULL); + + cJSON_Delete(root); +} + +static void cjson_add_true_should_add_true(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *true_item = NULL; + + cJSON_AddTrueToObject(root, "true"); + + TEST_ASSERT_NOT_NULL(true_item = cJSON_GetObjectItemCaseSensitive(root, "true")); + TEST_ASSERT_EQUAL_INT(true_item->type, cJSON_True); + + cJSON_Delete(root); +} + +static void cjson_add_false_should_add_false(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *false_item = NULL; + + cJSON_AddFalseToObject(root, "false"); + + TEST_ASSERT_NOT_NULL(false_item = cJSON_GetObjectItemCaseSensitive(root, "false")); + TEST_ASSERT_EQUAL_INT(false_item->type, cJSON_False); + + cJSON_Delete(root); +} + +static void cjson_add_bool_should_add_bool(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *true_item = NULL; + cJSON *false_item = NULL; + + /* true */ + cJSON_AddBoolToObject(root, "true", true); + TEST_ASSERT_NOT_NULL(true_item = cJSON_GetObjectItemCaseSensitive(root, "true")); + TEST_ASSERT_EQUAL_INT(true_item->type, cJSON_True); + + /* false */ + cJSON_AddBoolToObject(root, "false", false); + TEST_ASSERT_NOT_NULL(false_item = cJSON_GetObjectItemCaseSensitive(root, "false")); + TEST_ASSERT_EQUAL_INT(false_item->type, cJSON_False); + + cJSON_Delete(root); +} + +static void cjson_add_number_should_add_number(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *number = NULL; + + cJSON_AddNumberToObject(root, "number", 42); + + TEST_ASSERT_NOT_NULL(number = cJSON_GetObjectItemCaseSensitive(root, "number")); + + TEST_ASSERT_EQUAL_INT(number->type, cJSON_Number); + TEST_ASSERT_EQUAL_DOUBLE(number->valuedouble, 42); + TEST_ASSERT_EQUAL_INT(number->valueint, 42); + + cJSON_Delete(root); +} + +static void cjson_add_string_should_add_string(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *string = NULL; + + cJSON_AddStringToObject(root, "string", "Hello World!"); + + TEST_ASSERT_NOT_NULL(string = cJSON_GetObjectItemCaseSensitive(root, "string")); + TEST_ASSERT_EQUAL_INT(string->type, cJSON_String); + TEST_ASSERT_EQUAL_STRING(string->valuestring, "Hello World!"); + + cJSON_Delete(root); +} + +static void cjson_add_raw_should_add_raw(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *raw = NULL; + + cJSON_AddRawToObject(root, "raw", "{}"); + + TEST_ASSERT_NOT_NULL(raw = cJSON_GetObjectItemCaseSensitive(root, "raw")); + TEST_ASSERT_EQUAL_INT(raw->type, cJSON_Raw); + TEST_ASSERT_EQUAL_STRING(raw->valuestring, "{}"); + + cJSON_Delete(root); +} + +int main(void) +{ + UNITY_BEGIN(); + + RUN_TEST(cjson_add_null_should_add_null); + RUN_TEST(cjson_add_true_should_add_true); + RUN_TEST(cjson_add_false_should_add_false); + RUN_TEST(cjson_add_bool_should_add_bool); + RUN_TEST(cjson_add_number_should_add_number); + RUN_TEST(cjson_add_string_should_add_string); + + return UNITY_END(); +} From 5865faffa371b8334a28fb0d49c9d3ba8f43ced0 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 28 Dec 2017 23:56:39 +0100 Subject: [PATCH 090/307] Convert cJSON_Add...ToObject macros into functions These functions return the added object. Functions to add objects and arrays have also been added. --- cJSON.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++ cJSON.h | 16 ++++--- tests/cjson_add.c | 27 ++++++++++++ 3 files changed, 144 insertions(+), 7 deletions(-) diff --git a/cJSON.c b/cJSON.c index 79ce826d..e2272e66 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1958,6 +1958,114 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *str add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); } +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) { if ((parent == NULL) || (item == NULL)) diff --git a/cJSON.h b/cJSON.h index ba0b2587..17345131 100644 --- a/cJSON.h +++ b/cJSON.h @@ -246,13 +246,15 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons CJSON_PUBLIC(void) cJSON_Minify(char *json); /* Macros for creating things quickly. */ -#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) -#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) -#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) -#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) -#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) -#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) -#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s)) +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); /* When assigning an integer value, it needs to be propagated to valuedouble too. */ #define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) diff --git a/tests/cjson_add.c b/tests/cjson_add.c index 601d6664..03d39ef4 100644 --- a/tests/cjson_add.c +++ b/tests/cjson_add.c @@ -130,6 +130,30 @@ static void cjson_add_raw_should_add_raw(void) cJSON_Delete(root); } +static void cJSON_add_object_should_add_object(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *object = NULL; + + cJSON_AddObjectToObject(root, "object"); + TEST_ASSERT_NOT_NULL(object = cJSON_GetObjectItemCaseSensitive(root, "object")); + TEST_ASSERT_EQUAL_INT(object->type, cJSON_Object); + + cJSON_Delete(root); +} + +static void cJSON_add_array_should_add_array(void) +{ + cJSON *root = cJSON_CreateObject(); + cJSON *array = NULL; + + cJSON_AddArrayToObject(root, "array"); + TEST_ASSERT_NOT_NULL(array = cJSON_GetObjectItemCaseSensitive(root, "array")); + TEST_ASSERT_EQUAL_INT(array->type, cJSON_Array); + + cJSON_Delete(root); +} + int main(void) { UNITY_BEGIN(); @@ -140,6 +164,9 @@ int main(void) RUN_TEST(cjson_add_bool_should_add_bool); RUN_TEST(cjson_add_number_should_add_number); RUN_TEST(cjson_add_string_should_add_string); + RUN_TEST(cjson_add_raw_should_add_raw); + RUN_TEST(cJSON_add_object_should_add_object); + RUN_TEST(cJSON_add_array_should_add_array); return UNITY_END(); } From 77931e7fc0993c07cb2f4c1ade1aa23b9d01bb51 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 29 Dec 2017 23:26:53 +0100 Subject: [PATCH 091/307] cJSON_Add...ToObject: Add tests for failure conditions --- tests/cjson_add.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) diff --git a/tests/cjson_add.c b/tests/cjson_add.c index 03d39ef4..01668a94 100644 --- a/tests/cjson_add.c +++ b/tests/cjson_add.c @@ -28,6 +28,17 @@ #include "unity/src/unity.h" #include "common.h" +static void *failing_malloc(size_t size) +{ + (void)size; + return NULL; +} + +static cJSON_Hooks failing_hooks = { + failing_malloc, + free +}; + static void cjson_add_null_should_add_null(void) { cJSON *root = cJSON_CreateObject(); @@ -41,6 +52,29 @@ static void cjson_add_null_should_add_null(void) cJSON_Delete(root); } +static void cjson_add_null_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddNullToObject(NULL, "null")); + TEST_ASSERT_NULL(cJSON_AddNullToObject(root, NULL)); + + cJSON_Delete(root); +} + +static void cjson_add_null_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddNullToObject(root, "null")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cjson_add_true_should_add_true(void) { cJSON *root = cJSON_CreateObject(); @@ -54,6 +88,29 @@ static void cjson_add_true_should_add_true(void) cJSON_Delete(root); } +static void cjson_add_true_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddTrueToObject(NULL, "true")); + TEST_ASSERT_NULL(cJSON_AddTrueToObject(root, NULL)); + + cJSON_Delete(root); +} + +static void cjson_add_true_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddTrueToObject(root, "true")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cjson_add_false_should_add_false(void) { cJSON *root = cJSON_CreateObject(); @@ -67,6 +124,29 @@ static void cjson_add_false_should_add_false(void) cJSON_Delete(root); } +static void cjson_add_false_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddFalseToObject(NULL, "false")); + TEST_ASSERT_NULL(cJSON_AddFalseToObject(root, NULL)); + + cJSON_Delete(root); +} + +static void cjson_add_false_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddFalseToObject(root, "false")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cjson_add_bool_should_add_bool(void) { cJSON *root = cJSON_CreateObject(); @@ -86,6 +166,29 @@ static void cjson_add_bool_should_add_bool(void) cJSON_Delete(root); } +static void cjson_add_bool_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddBoolToObject(NULL, "false", false)); + TEST_ASSERT_NULL(cJSON_AddBoolToObject(root, NULL, false)); + + cJSON_Delete(root); +} + +static void cjson_add_bool_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddBoolToObject(root, "false", false)); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cjson_add_number_should_add_number(void) { cJSON *root = cJSON_CreateObject(); @@ -102,6 +205,29 @@ static void cjson_add_number_should_add_number(void) cJSON_Delete(root); } +static void cjson_add_number_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddNumberToObject(NULL, "number", 42)); + TEST_ASSERT_NULL(cJSON_AddNumberToObject(root, NULL, 42)); + + cJSON_Delete(root); +} + +static void cjson_add_number_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddNumberToObject(root, "number", 42)); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cjson_add_string_should_add_string(void) { cJSON *root = cJSON_CreateObject(); @@ -116,6 +242,29 @@ static void cjson_add_string_should_add_string(void) cJSON_Delete(root); } +static void cjson_add_string_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddStringToObject(NULL, "string", "string")); + TEST_ASSERT_NULL(cJSON_AddStringToObject(root, NULL, "string")); + + cJSON_Delete(root); +} + +static void cjson_add_string_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddStringToObject(root, "string", "string")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cjson_add_raw_should_add_raw(void) { cJSON *root = cJSON_CreateObject(); @@ -130,6 +279,29 @@ static void cjson_add_raw_should_add_raw(void) cJSON_Delete(root); } +static void cjson_add_raw_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddRawToObject(NULL, "raw", "{}")); + TEST_ASSERT_NULL(cJSON_AddRawToObject(root, NULL, "{}")); + + cJSON_Delete(root); +} + +static void cjson_add_raw_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddRawToObject(root, "raw", "{}")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cJSON_add_object_should_add_object(void) { cJSON *root = cJSON_CreateObject(); @@ -142,6 +314,29 @@ static void cJSON_add_object_should_add_object(void) cJSON_Delete(root); } +static void cjson_add_object_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddObjectToObject(NULL, "object")); + TEST_ASSERT_NULL(cJSON_AddObjectToObject(root, NULL)); + + cJSON_Delete(root); +} + +static void cjson_add_object_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddObjectToObject(root, "object")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + static void cJSON_add_array_should_add_array(void) { cJSON *root = cJSON_CreateObject(); @@ -154,19 +349,68 @@ static void cJSON_add_array_should_add_array(void) cJSON_Delete(root); } +static void cjson_add_array_should_fail_with_null_pointers(void) +{ + cJSON *root = cJSON_CreateObject(); + + TEST_ASSERT_NULL(cJSON_AddArrayToObject(NULL, "array")); + TEST_ASSERT_NULL(cJSON_AddArrayToObject(root, NULL)); + + cJSON_Delete(root); +} + +static void cjson_add_array_should_fail_on_allocation_failure(void) +{ + cJSON *root = cJSON_CreateObject(); + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_AddArrayToObject(root, "array")); + + cJSON_InitHooks(NULL); + + cJSON_Delete(root); +} + int main(void) { UNITY_BEGIN(); RUN_TEST(cjson_add_null_should_add_null); + RUN_TEST(cjson_add_null_should_fail_with_null_pointers); + RUN_TEST(cjson_add_null_should_fail_on_allocation_failure); + RUN_TEST(cjson_add_true_should_add_true); + RUN_TEST(cjson_add_true_should_fail_with_null_pointers); + RUN_TEST(cjson_add_true_should_fail_on_allocation_failure); + RUN_TEST(cjson_add_false_should_add_false); + RUN_TEST(cjson_add_false_should_fail_with_null_pointers); + RUN_TEST(cjson_add_false_should_fail_on_allocation_failure); + RUN_TEST(cjson_add_bool_should_add_bool); + RUN_TEST(cjson_add_bool_should_fail_with_null_pointers); + RUN_TEST(cjson_add_bool_should_fail_on_allocation_failure); + RUN_TEST(cjson_add_number_should_add_number); + RUN_TEST(cjson_add_number_should_fail_with_null_pointers); + RUN_TEST(cjson_add_number_should_fail_on_allocation_failure); + RUN_TEST(cjson_add_string_should_add_string); + RUN_TEST(cjson_add_string_should_fail_with_null_pointers); + RUN_TEST(cjson_add_string_should_fail_on_allocation_failure); + RUN_TEST(cjson_add_raw_should_add_raw); + RUN_TEST(cjson_add_raw_should_fail_with_null_pointers); + RUN_TEST(cjson_add_raw_should_fail_on_allocation_failure); + RUN_TEST(cJSON_add_object_should_add_object); + RUN_TEST(cjson_add_object_should_fail_with_null_pointers); + RUN_TEST(cjson_add_object_should_fail_on_allocation_failure); + RUN_TEST(cJSON_add_array_should_add_array); + RUN_TEST(cjson_add_array_should_fail_with_null_pointers); + RUN_TEST(cjson_add_array_should_fail_on_allocation_failure); return UNITY_END(); } From 1b21bcd150145ac83351a159d82e4f712ac544b7 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 29 Dec 2017 23:29:09 +0100 Subject: [PATCH 092/307] cJSON_Add..ToObject: Add comment to header file --- cJSON.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cJSON.h b/cJSON.h index 17345131..c3d8c76b 100644 --- a/cJSON.h +++ b/cJSON.h @@ -245,7 +245,8 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons CJSON_PUBLIC(void) cJSON_Minify(char *json); -/* Macros for creating things quickly. */ +/* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); From c31ee79ad1de522a8766bf02f9f10e568d7523e9 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 10 Nov 2017 21:36:05 +0100 Subject: [PATCH 093/307] README: new doc: Data Structure section --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/README.md b/README.md index 82245cba..5a793922 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Ultralightweight JSON parser in ANSI C. * [Welcome to cJSON](#welcome-to-cjson) * [Building](#building) * [Including cJSON](#including-cjson) + * [Data Structure](#data-structure) * [Some JSON](#some-json) * [Here's the structure](#heres-the-structure) * [Caveats](#caveats) @@ -123,6 +124,45 @@ If you installed it via CMake or the Makefile, you can include cJSON like this: #include ``` +### Data Structure + +cJSON represents JSON data using the `cJSON` struct data type: + +```c +/* The cJSON structure: */ +typedef struct cJSON +{ + struct cJSON *next; + struct cJSON *prev; + struct cJSON *child; + int type; + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + double valuedouble; + char *string; +} cJSON; +``` + +An item of this type represents a JSON value. The type is stored in `type` as a bit-flag (**this means that you cannot find out the type by just comparing the value of `type`**). + +To check the type of an item, use the corresponding `cJSON_Is...` function. It does a `NULL` check followed by a type check and returns a boolean value if the item is of this type. + +The type can be one of the following: +* `cJSON_Invalid` (check with `cJSON_IsInvalid`): Represents an invalid item that doesn't contain any value. You automatically have this type if you set the item to all zero bytes. +* `cJSON_False` (check with `cJSON_IsFalse`): Represents a `false` boolean value. You can also check for boolean values in general with `cJSON_IsBool`. +* `cJSON_True` (check with `cJSON_IsTrue`): Represents a `true` boolean value. You can also check for boolean values in general with `cJSON_IsBool`. +* `cJSON_NULL` (check with `cJSON_IsNull`): Represents a `null` value. +* `cJSON_Number` (check with `cJSON_IsNumber`): Represents a number value. The value is stored as a double in `valuedouble` and also in `valueint`. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` are used for `valueint`. +* `cJSON_String` (check with `cJSON_IsString`): Represents a string value. It is stored in the form of a zero terminated string in `valuestring`. +* `cJSON_Array` (check with `cJSON_IsArray`): Represent an array value. This is implemented by pointing `child` to a linked list of `cJSON` items that represent the values in the array. The elements are linked together using `next` and `prev`, where the first element has `prev == NULL` and the last element `next == NULL`. +* `cJSON_Object` (check with `cJSON_IsObject`): Represents an object value. Objects are stored same way as an array, the only difference is that the items in the object store their keys in `string`. +* `cJSON_Raw` (check with `cJSON_IsRaw`): Represents any kind of JSON that is stored as a zero terminated array of characters in `valuestring`. This can be used, for example, to avoid printing the same static JSON over and over again to save performance. cJSON will never create this type when parsing. Also note that cJSON doesn't check if it is valid JSON. + +Additionally there are the following two flags: +* `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not it's children/valuestring. +* `cJSON_StringIsConst`: This means that `string` points to a constant string. This means that `cJSON_Delete` and other functions will not try to deallocate `string`. + ### Some JSON: ```json From b54b81251e62f9bebe4d981afcee22335ba44ddf Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 10 Nov 2017 22:08:57 +0100 Subject: [PATCH 094/307] README: new doc: Parsing --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 5a793922..93af9dd1 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Ultralightweight JSON parser in ANSI C. * [Building](#building) * [Including cJSON](#including-cjson) * [Data Structure](#data-structure) + * [Parsing JSON](#parsing-json) * [Some JSON](#some-json) * [Here's the structure](#heres-the-structure) * [Caveats](#caveats) @@ -163,6 +164,24 @@ Additionally there are the following two flags: * `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not it's children/valuestring. * `cJSON_StringIsConst`: This means that `string` points to a constant string. This means that `cJSON_Delete` and other functions will not try to deallocate `string`. +### Parsing JSON + +Given some JSON in a zero terminated string, you can parse it with `cJSON_Parse`. + +```c +cJSON *json = cJSON_Parse(string); +``` + +It will parse the JSON and allocate a tree of `cJSON` items that represents it. Once it returns, you are fully responsible for deallocating it after use with `cJSON_Delete`. + +The allocator used by `cJSON_Parse` is `malloc` and `free` by default but can be changed (globally) with `cJSON_InitHooks`. + +If an error occurs a pointer to the position of the error in the input string can be accessed using `cJSON_GetErrorPtr`. Note though that this can produce race conditions in multithreading scenarios, in that case it is better to use `cJSON_ParseWithOpts` with `return_parse_end`. +By default, characters in the input string that follow the parsed JSON will not be considered as an error. + +If you want more options, use `cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)`. +`return_parse_end` returns a pointer to the end of the JSON in the input string or the position that an error occurs at (thereby replacing `cJSON_GetErrorPtr` in a thread safe way). `require_null_terminated`, if set to `1` will make it an error if the input string contains data after the JSON. + ### Some JSON: ```json From 1285e6ac6889a62c06ffb8da74d8e9a5fc265b74 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 11 Nov 2017 13:07:05 +0100 Subject: [PATCH 095/307] README: new doc: Printing --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 93af9dd1..2994af47 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Ultralightweight JSON parser in ANSI C. * [Including cJSON](#including-cjson) * [Data Structure](#data-structure) * [Parsing JSON](#parsing-json) + * [Printing JSON](#printing-json) * [Some JSON](#some-json) * [Here's the structure](#heres-the-structure) * [Caveats](#caveats) @@ -182,6 +183,22 @@ By default, characters in the input string that follow the parsed JSON will not If you want more options, use `cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)`. `return_parse_end` returns a pointer to the end of the JSON in the input string or the position that an error occurs at (thereby replacing `cJSON_GetErrorPtr` in a thread safe way). `require_null_terminated`, if set to `1` will make it an error if the input string contains data after the JSON. +### Printing JSON + +Given a tree of `cJSON` items, you can print them as a string using `cJSON_Print`. + +```c +char *string = cJSON_Print(json); +``` + +It will allocate a string and print a JSON representation of the tree into it. Once it returns, you are fully responsible for deallocating it after use with your allocator. (usually `free`, depends on what has been set with `cJSON_InitHooks`). + +`cJSON_Print` will print with whitespace for formatting. If you want to print without formatting, use `cJSON_PrintUnformatted`. + +If you have a rough idea of how big your resulting string will be, you can use `cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)`. `fmt` is a boolean to turn formatting with whitespace on and off. `prebuffer` specifies the first buffer size to use for printing. `cJSON_Print` currently uses 256 bytes for it's first buffer size. Once printing runs out of space, a new buffer is allocated and the old gets copied over before printing is continued. + +These dynamic buffer allocations can be completely avoided by using `cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)`. It takes a buffer to a pointer to print to and it's length. If the length is reached, printing will fail and it returns `0`. In case of success, `1` is returned. Note that you should provide 5 bytes more than is actually needed, because cJSON is not 100% accurate in estimating if the provided memory is enough. + ### Some JSON: ```json From 61dd7f1e413a10f8a67b96da5c15f447aba5b763 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 15 Nov 2017 18:07:54 +0100 Subject: [PATCH 096/307] README: new doc: Working with the data structure --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/README.md b/README.md index 2994af47..e904de16 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Ultralightweight JSON parser in ANSI C. * [Building](#building) * [Including cJSON](#including-cjson) * [Data Structure](#data-structure) + * [Working with the data structure](#working-with-the-data-structure) * [Parsing JSON](#parsing-json) * [Printing JSON](#printing-json) * [Some JSON](#some-json) @@ -165,6 +166,58 @@ Additionally there are the following two flags: * `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not it's children/valuestring. * `cJSON_StringIsConst`: This means that `string` points to a constant string. This means that `cJSON_Delete` and other functions will not try to deallocate `string`. +### Working with the data structure + +For every value type there is a `cJSON_Create...` function that can be used to create an item of that type. +All of these will allocate a `cJSON` struct that can later be deleted with `cJSON_Delete`. +Note that you have to delete them at some point, otherwise you will get a memory leak. +**Important**: If you have added an item to an array or an object already, you **mustn't** delete it with `cJSON_Delete`. Adding it to an array or object transfers its ownership so that when that array or object is deleted, it gets deleted as well. + +#### Basic types +* **null** is created with `cJSON_CreateNull` +* **booleans** are created with `cJSON_CreateTrue`, `cJSON_CreateFalse` or `cJSON_CreateBool` +* **numbers** are created with `cJSON_CreateNumber`. This will set both `valuedouble` and `valueint`. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` are used for `valueint` +* **strings** are created with `cJSON_CreateString` (copies the string) or with `cJSON_CreateStringReference` (directly points to the string. This means that `valuestring` won't be deleted by `cJSON_Delete` and you are responsible for it's lifetime, useful for constants) + +#### Arrays + +You can create an empty array with `cJSON_CreateArray`. `cJSON_CreateArrayReference` can be used to create an array that doesn't "own" its content, so its content doesn't get deleted by `cJSON_Delete`. + +To add items to an array, use `cJSON_AddItemToArray` to append items to the end. +Using `cJSON_AddItemReferenceToArray` an element can be added as a reference to another item, array or string. This means that `cJSON_Delete` will not delete that items `child` or `valuestring` properties, so no double frees are occuring if they are already used elsewhere. +To insert items in the middle, use `cJSON_InsertItemInArray`. It will insert an item at the given 0 based index and shift all the existing items to the right. + +If you want to take an item out of an array at a given index and continue using it, use `cJSON_DetachItemFromArray`, it will return the detached item, so be sure to assign it to a pointer, otherwise you will have a memory leak. + +Deleting items is done with `cJSON_DeleteItemFromArray`. It works like `cJSON_DetachItemFromArray`, but deletes the detached item via `cJSON_Delete`. + +You can also replace an item in an array in place. Either with `cJSON_ReplaceItemInArray` using an index or with `cJSON_ReplaceItemViaPointer` given a pointer to an element. `cJSON_ReplaceItemViaPointer` will return `0` if it fails. What this does internally is to detach the old item, delete it and insert the new item in its place. + +To get the size of an array, use `cJSON_GetArraySize`. Use `cJSON_GetArrayItem` to get an element at a given index. + +Because an array is stored as a linked list, iterating it via index is inefficient (`O(n²)`), so you can iterate over an array using the `cJSON_ArrayForEach` macro in `O(n)` time complexity. + +#### Objects + +You can create an empty object with `cJSON_CreateObject`. `cJSON_CreateObjectReference` can be used to create an object that doesn't "own" its content, so its content doesn't get deleted by `cJSON_Delete`. + +To add items to an object, use `cJSON_AddItemToObject`. Use `cJSON_AddItemToObjectCS` to add an item to an object with a name that is a constant or reference (key of the item, `string` in the `cJSON` struct), so that it doesn't get freed by `cJSON_Delete`. +Using `cJSON_AddItemReferenceToArray` an element can be added as a reference to another object, array or string. This means that `cJSON_Delete` will not delete that items `child` or `valuestring` properties, so no double frees are occuring if they are already used elsewhere. + +If you want to take an item out of an object, use `cJSON_DetachItemFromObjectCaseSensitive`, it will return the detached item, so be sure to assign it to a pointer, otherwise you will have a memory leak. + +Deleting items is done with `cJSON_DeleteItemFromObjectCaseSensitive`. It works like `cJSON_DetachItemFromObjectCaseSensitive` followed by `cJSON_Delete`. + +You can also replace an item in an object in place. Either with `cJSON_ReplaceItemInObjectCaseSensitive` using a key or with `cJSON_ReplaceItemViaPointer` given a pointer to an element. `cJSON_ReplaceItemViaPointer` will return `0` if it fails. What this does internally is to detach the old item, delete it and insert the new item in its place. + +To get the size of an object, you can use `cJSON_GetArraySize`, this works because internally objects are stored as arrays. + +If you want to access an item in an object, use `cJSON_GetObjectItemCaseSensitive`. + +To iterate over an object, you can use the `cJSON_ArrayForEach` macro the same way as for arrays. + +cJSON also provides convenient helper functions for quickly creating a new item and adding it to an object, like `cJSON_AddNullToObject`. They return a pointer to the new item or `NULL` if they failed. + ### Parsing JSON Given some JSON in a zero terminated string, you can parse it with `cJSON_Parse`. From cdcd5537697467ff533e8b8b9248a019195af930 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 20 Dec 2017 02:42:30 +0100 Subject: [PATCH 097/307] README: new doc: Example --- README.md | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) diff --git a/README.md b/README.md index e904de16..8435e1e1 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Ultralightweight JSON parser in ANSI C. * [Working with the data structure](#working-with-the-data-structure) * [Parsing JSON](#parsing-json) * [Printing JSON](#printing-json) + * [Example](#example) * [Some JSON](#some-json) * [Here's the structure](#heres-the-structure) * [Caveats](#caveats) @@ -252,6 +253,216 @@ If you have a rough idea of how big your resulting string will be, you can use ` These dynamic buffer allocations can be completely avoided by using `cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)`. It takes a buffer to a pointer to print to and it's length. If the length is reached, printing will fail and it returns `0`. In case of success, `1` is returned. Note that you should provide 5 bytes more than is actually needed, because cJSON is not 100% accurate in estimating if the provided memory is enough. +### Example +In this example we want to build and parse the following JSON: + +```json +{ + "name": "Awesome 4K", + "resolutions": [ + { + "width": 1280, + "height": 720 + }, + { + "width": 1920, + "height": 1080 + }, + { + "width": 3840, + "height": 2160 + } + ] +} +``` + +#### Printing +Let's build the above JSON and print it to a string: +```c +//create a monitor with a list of supported resolutions +char* create_monitor(void) +{ + const unsigned int resolution_numbers[3][2] = { + {1280, 720}, + {1920, 1080}, + {3840, 2160} + }; + char *string = NULL; + cJSON *name = NULL; + cJSON *resolutions = NULL; + cJSON *resolution = NULL; + cJSON *width = NULL; + cJSON *height = NULL; + size_t index = 0; + + cJSON *monitor = cJSON_CreateObject(); + if (monitor == NULL) + { + goto end; + } + + name = cJSON_CreateString("Awesome 4K"); + if (name == NULL) + { + goto end; + } + /* after creation was successful, immediately add it to the monitor, + * thereby transfering ownership of the pointer to it */ + cJSON_AddItemToObject(monitor, "name", name); + + resolutions = cJSON_CreateArray(); + if (resolutions == NULL) + { + goto end; + } + cJSON_AddItemToObject(monitor, "resolutions", resolutions); + + for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index) + { + resolution = cJSON_CreateObject(); + if (resolution == NULL) + { + goto end; + } + cJSON_AddItemToArray(resolutions, resolution); + + width = cJSON_CreateNumber(resolution_numbers[index][0]); + if (width == NULL) + { + goto end; + } + cJSON_AddItemToObject(resolution, "width", width); + + height = cJSON_CreateNumber(resolution_numbers[index][1]); + if (height == NULL) + { + goto end; + } + cJSON_AddItemToObject(resolution, "height", height); + } + + string = cJSON_Print(monitor); + if (string == NULL) + { + fprintf(stderr, "Failed to print monitor.\n"); + } + +end: + cJSON_Delete(monitor); + return string; +} +``` + +Alternatively we can use the `cJSON_Add...ToObject` helper functions to make our lifes a little easier: +```c +char *create_monitor_with_helpers(void) +{ + const unsigned int resolution_numbers[3][2] = { + {1280, 720}, + {1920, 1080}, + {3840, 2160} + }; + char *string = NULL; + cJSON *resolutions = NULL; + size_t index = 0; + + cJSON *monitor = cJSON_CreateObject(); + + if (cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL) + { + goto end; + } + + resolutions = cJSON_AddArrayToObject(monitor, "resolutions"); + if (resolutions == NULL) + { + goto end; + } + + for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index) + { + cJSON *resolution = cJSON_CreateObject(); + + if (cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0]) == NULL) + { + goto end; + } + + if(cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL) + { + goto end; + } + + cJSON_AddItemToArray(resolutions, resolution); + } + + string = cJSON_Print(monitor); + if (string == NULL) { + fprintf(stderr, "Failed to print monitor.\n"); + } + +end: + cJSON_Delete(monitor); + return string; +} +``` + +#### Parsing +In this example we will parse a JSON in the above format and check if the monitor supports a Full HD resolution while printing some diagnostic output: + +```c +/* return 1 if the monitor supports full hd, 0 otherwise */ +int supports_full_hd(const char * const monitor) +{ + const cJSON *resolution = NULL; + const cJSON *resolutions = NULL; + const cJSON *name = NULL; + int status = 0; + cJSON *monitor_json = cJSON_Parse(monitor); + if (monitor_json == NULL) + { + const char *error_ptr = cJSON_GetErrorPtr(); + if (error_ptr != NULL) + { + fprintf(stderr, "Error before: %s\n", error_ptr); + } + status = 0; + goto end; + } + + name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name"); + if (cJSON_IsString(name) && (name->valuestring != NULL)) + { + printf("Checking monitor \"%s\"\n", name->valuestring); + } + + resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions"); + cJSON_ArrayForEach(resolution, resolutions) + { + cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width"); + cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height"); + + if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height)) + { + status = 0; + goto end; + } + + if ((width->valuedouble == 1920) && (height->valuedouble == 1080)) + { + status = 1; + goto end; + } + } + +end: + cJSON_Delete(monitor_json); + return status; +} +``` + +Note that there are no NULL checks except for the result of `cJSON_Parse` because `cJSON_GetObjectItemCaseSensitive` checks for `NULL` inputs already, so a `NULL` value is just propagated and `cJSON_IsNumber` and `cJSON_IsString` return `0` if the input is `NULL`. + ### Some JSON: ```json From 5605fa4ad5d1a162e14fcb5bbab8a90b1b4803ce Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 30 Dec 2017 01:54:27 +0100 Subject: [PATCH 098/307] README: new doc: Remove old explanation. --- README.md | 271 +----------------------------------------------------- 1 file changed, 3 insertions(+), 268 deletions(-) diff --git a/README.md b/README.md index 8435e1e1..aa345e7e 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,6 @@ Ultralightweight JSON parser in ANSI C. * [Parsing JSON](#parsing-json) * [Printing JSON](#printing-json) * [Example](#example) - * [Some JSON](#some-json) - * [Here's the structure](#heres-the-structure) * [Caveats](#caveats) * [Enjoy cJSON!](#enjoy-cjson) @@ -463,270 +461,6 @@ end: Note that there are no NULL checks except for the result of `cJSON_Parse` because `cJSON_GetObjectItemCaseSensitive` checks for `NULL` inputs already, so a `NULL` value is just propagated and `cJSON_IsNumber` and `cJSON_IsString` return `0` if the input is `NULL`. -### Some JSON: - -```json -{ - "name": "Jack (\"Bee\") Nimble", - "format": { - "type": "rect", - "width": 1920, - "height": 1080, - "interlace": false, - "frame rate": 24 - } -} -``` - -Assume that you got this from a file, a webserver, or magic JSON elves, whatever, -you have a `char *` to it. Everything is a `cJSON` struct. -Get it parsed: - -```c -cJSON * root = cJSON_Parse(my_json_string); -``` - -This is an object. We're in C. We don't have objects. But we do have structs. -What's the framerate? - -```c -cJSON *format = cJSON_GetObjectItemCaseSensitive(root, "format"); -cJSON *framerate_item = cJSON_GetObjectItemCaseSensitive(format, "frame rate"); -double framerate = 0; -if (cJSON_IsNumber(framerate_item)) -{ - framerate = framerate_item->valuedouble; -} -``` - -Want to change the framerate? - -```c -cJSON *framerate_item = cJSON_GetObjectItemCaseSensitive(format, "frame rate"); -cJSON_SetNumberValue(framerate_item, 25); -``` - -Back to disk? - -```c -char *rendered = cJSON_Print(root); -``` - -Finished? Delete the root (this takes care of everything else). - -```c -cJSON_Delete(root); -``` - -That's AUTO mode. If you're going to use Auto mode, you really ought to check pointers -before you dereference them. If you want to see how you'd build this struct in code? - -```c -cJSON *root; -cJSON *fmt; -root = cJSON_CreateObject(); -cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble")); -cJSON_AddItemToObject(root, "format", fmt = cJSON_CreateObject()); -cJSON_AddStringToObject(fmt, "type", "rect"); -cJSON_AddNumberToObject(fmt, "width", 1920); -cJSON_AddNumberToObject(fmt, "height", 1080); -cJSON_AddFalseToObject (fmt, "interlace"); -cJSON_AddNumberToObject(fmt, "frame rate", 24); -``` - -Hopefully we can agree that's not a lot of code? There's no overhead, no unnecessary setup. -Look at `test.c` for a bunch of nice examples, mostly all ripped off the [json.org](http://json.org) site, and -a few from elsewhere. - -What about manual mode? First up you need some detail. -Let's cover how the `cJSON` objects represent the JSON data. -cJSON doesn't distinguish arrays from objects in handling; just type. -Each `cJSON` has, potentially, a child, siblings, value, a name. - -* The `root` object has: *Object* Type and a Child -* The Child has name "name", with value "Jack ("Bee") Nimble", and a sibling: -* Sibling has type *Object*, name "format", and a child. -* That child has type *String*, name "type", value "rect", and a sibling: -* Sibling has type *Number*, name "width", value 1920, and a sibling: -* Sibling has type *Number*, name "height", value 1080, and a sibling: -* Sibling has type *False*, name "interlace", and a sibling: -* Sibling has type *Number*, name "frame rate", value 24 - -### Here's the structure: - -```c -typedef struct cJSON { - struct cJSON *next,*prev; - struct cJSON *child; - - int type; - - char *valuestring; - int valueint; /* writing to valueint is DEPRECATED, please use cJSON_SetNumberValue instead */ - double valuedouble; - - char *string; -} cJSON; -``` - -By default all values are 0 unless set by virtue of being meaningful. - -`next`/`prev` is a doubly linked list of siblings. `next` takes you to your sibling, -`prev` takes you back from your sibling to you. -Only objects and arrays have a `child`, and it's the head of the doubly linked list. -A `child` entry will have `prev == 0`, but next potentially points on. The last sibling has `next == 0`. -The type expresses *Null*/*True*/*False*/*Number*/*String*/*Array*/*Object*, all of which are `#defined` in -`cJSON.h`. - -A *Number* has `valueint` and `valuedouble`. `valueint` is a relict of the past, so always use `valuedouble`. - -Any entry which is in the linked list which is the child of an object will have a `string` -which is the "name" of the entry. When I said "name" in the above example, that's `string`. -`string` is the JSON name for the 'variable name' if you will. - -Now you can trivially walk the lists, recursively, and parse as you please. -You can invoke `cJSON_Parse` to get cJSON to parse for you, and then you can take -the root object, and traverse the structure (which is, formally, an N-tree), -and tokenise as you please. If you wanted to build a callback style parser, this is how -you'd do it (just an example, since these things are very specific): - -```c -void parse_and_callback(cJSON *item, const char *prefix) -{ - while (item) - { - char *newprefix = malloc(strlen(prefix) + strlen(item->string) + 2); - sprintf(newprefix, "%s/%s", prefix, item->string); - int dorecurse = callback(newprefix, item->type, item); - if (item->child && dorecurse) - { - parse_and_callback(item->child, newprefix); - } - item = item->next; - free(newprefix); - } -} -``` - -The `prefix` process will build you a separated list, to simplify your callback handling. -The `dorecurse` flag would let the callback decide to handle sub-arrays on it's own, or -let you invoke it per-item. For the item above, your callback might look like this: - -```c -int callback(const char *name, int type, cJSON *item) -{ - if (!strcmp(name, "name")) - { - /* populate name */ - } - else if (!strcmp(name, "format/type")) - { - /* handle "rect" */ } - else if (!strcmp(name, "format/width")) - { - /* 800 */ - } - else if (!strcmp(name, "format/height")) - { - /* 600 */ - } - else if (!strcmp(name, "format/interlace")) - { - /* false */ - } - else if (!strcmp(name, "format/frame rate")) - { - /* 24 */ - } - - return 1; -} -``` - -Alternatively, you might like to parse iteratively. -You'd use: - -```c -void parse_object(cJSON *item) -{ - int i; - for (i = 0; i < cJSON_GetArraySize(item); i++) - { - cJSON *subitem = cJSON_GetArrayItem(item, i); - // handle subitem - } -} -``` - -Or, for PROPER manual mode: - -```c -void parse_object(cJSON *item) -{ - cJSON *subitem = item->child; - while (subitem) - { - // handle subitem - if (subitem->child) - { - parse_object(subitem->child); - } - - subitem = subitem->next; - } -} -``` - -Of course, this should look familiar, since this is just a stripped-down version -of the callback-parser. - -This should cover most uses you'll find for parsing. The rest should be possible -to infer.. and if in doubt, read the source! There's not a lot of it! ;) - -In terms of constructing JSON data, the example code above is the right way to do it. -You can, of course, hand your sub-objects to other functions to populate. -Also, if you find a use for it, you can manually build the objects. -For instance, suppose you wanted to build an array of objects? - -```c -cJSON *objects[24]; - -cJSON *Create_array_of_anything(cJSON **items, int num) -{ - int i; - cJSON *prev; - cJSON *root = cJSON_CreateArray(); - for (i = 0; i < 24; i++) - { - if (!i) - { - root->child = objects[i]; - } - else - { - prev->next = objects[i]; - objects[i]->prev = prev; - } - - prev = objects[i]; - } - - return root; -} -``` - -and simply: `Create_array_of_anything(objects, 24);` - -cJSON doesn't make any assumptions about what order you create things in. -You can attach the objects, as above, and later add children to each -of those objects. - -As soon as you call `cJSON_Print`, it renders the structure to text. - -The `test.c` code shows how to handle a bunch of typical cases. If you uncomment -the code, it'll load, parse and print a bunch of test files, also from [json.org](http://json.org), -which are more complex than I'd care to try and stash into a `const char array[]`. - ### Caveats #### Zero Character @@ -768,5 +502,6 @@ When cJSON was originally created, it didn't follow the JSON standard and didn't # Enjoy cJSON! -- Dave Gamble, Aug 2009 -- [cJSON contributors](CONTRIBUTORS.md) +- Dave Gamble (original author) +- Max Bruckner (current maintainer) +- and the other [cJSON contributors](CONTRIBUTORS.md) From e7d0c1dc375f74937844f01b0352a236856ccf69 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 30 Dec 2017 02:24:06 +0100 Subject: [PATCH 099/307] Tests: Test if the readme examples are working --- tests/CMakeLists.txt | 1 + tests/readme_examples.c | 258 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+) create mode 100644 tests/readme_examples.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 01496f87..79672927 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -56,6 +56,7 @@ if(ENABLE_CJSON_TEST) parse_with_opts compare_tests cjson_add + readme_examples ) option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.") diff --git a/tests/readme_examples.c b/tests/readme_examples.c new file mode 100644 index 00000000..f3fa4438 --- /dev/null +++ b/tests/readme_examples.c @@ -0,0 +1,258 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include +#include + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" + +static const char *json = "{\n\ +\t\"name\":\t\"Awesome 4K\",\n\ +\t\"resolutions\":\t[{\n\ +\t\t\t\"width\":\t1280,\n\ +\t\t\t\"height\":\t720\n\ +\t\t}, {\n\ +\t\t\t\"width\":\t1920,\n\ +\t\t\t\"height\":\t1080\n\ +\t\t}, {\n\ +\t\t\t\"width\":\t3840,\n\ +\t\t\t\"height\":\t2160\n\ +\t\t}]\n\ +}"; + +static char* create_monitor(void) +{ + const unsigned int resolution_numbers[3][2] = { + {1280, 720}, + {1920, 1080}, + {3840, 2160} + }; + char *string = NULL; + cJSON *name = NULL; + cJSON *resolutions = NULL; + cJSON *resolution = NULL; + cJSON *width = NULL; + cJSON *height = NULL; + size_t index = 0; + + cJSON *monitor = cJSON_CreateObject(); + if (monitor == NULL) + { + goto end; + } + + name = cJSON_CreateString("Awesome 4K"); + if (name == NULL) + { + goto end; + } + /* after creation was successful, immediately add it to the monitor, + * thereby transfering ownership of the pointer to it */ + cJSON_AddItemToObject(monitor, "name", name); + + resolutions = cJSON_CreateArray(); + if (resolutions == NULL) + { + goto end; + } + cJSON_AddItemToObject(monitor, "resolutions", resolutions); + + for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index) + { + resolution = cJSON_CreateObject(); + if (resolution == NULL) + { + goto end; + } + cJSON_AddItemToArray(resolutions, resolution); + + width = cJSON_CreateNumber(resolution_numbers[index][0]); + if (width == NULL) + { + goto end; + } + cJSON_AddItemToObject(resolution, "width", width); + + height = cJSON_CreateNumber(resolution_numbers[index][1]); + if (height == NULL) + { + goto end; + } + cJSON_AddItemToObject(resolution, "height", height); + } + + string = cJSON_Print(monitor); + if (string == NULL) + { + fprintf(stderr, "Failed to print monitor.\n"); + } + +end: + cJSON_Delete(monitor); + return string; +} + +static char *create_monitor_with_helpers(void) +{ + const unsigned int resolution_numbers[3][2] = { + {1280, 720}, + {1920, 1080}, + {3840, 2160} + }; + char *string = NULL; + cJSON *resolutions = NULL; + size_t index = 0; + + cJSON *monitor = cJSON_CreateObject(); + + if (cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL) + { + goto end; + } + + resolutions = cJSON_AddArrayToObject(monitor, "resolutions"); + if (resolutions == NULL) + { + goto end; + } + + for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index) + { + cJSON *resolution = cJSON_CreateObject(); + + if (cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0]) == NULL) + { + goto end; + } + + if(cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL) + { + goto end; + } + + cJSON_AddItemToArray(resolutions, resolution); + } + + string = cJSON_Print(monitor); + if (string == NULL) { + fprintf(stderr, "Failed to print monitor.\n"); + } + +end: + cJSON_Delete(monitor); + return string; +} + +/* return 1 if the monitor supports full hd, 0 otherwise */ +static int supports_full_hd(const char * const monitor) +{ + const cJSON *resolution = NULL; + const cJSON *resolutions = NULL; + const cJSON *name = NULL; + int status = 0; + cJSON *monitor_json = cJSON_Parse(monitor); + if (monitor_json == NULL) + { + const char *error_ptr = cJSON_GetErrorPtr(); + if (error_ptr != NULL) + { + fprintf(stderr, "Error before: %s\n", error_ptr); + } + status = 0; + goto end; + } + + name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name"); + if (cJSON_IsString(name) && (name->valuestring != NULL)) + { + printf("Checking monitor \"%s\"\n", name->valuestring); + } + + resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions"); + cJSON_ArrayForEach(resolution, resolutions) + { + cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width"); + cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height"); + + if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height)) + { + status = 0; + goto end; + } + + if ((width->valuedouble == 1920) && (height->valuedouble == 1080)) + { + status = 1; + goto end; + } + } + +end: + cJSON_Delete(monitor_json); + return status; +} + +static void create_monitor_should_create_a_monitor(void) +{ + char *monitor = create_monitor(); + + TEST_ASSERT_EQUAL_STRING(monitor, json); + + free(monitor); +} + +static void create_monitor_with_helpers_should_create_a_monitor(void) +{ + char *monitor = create_monitor_with_helpers(); + + TEST_ASSERT_EQUAL_STRING(json, monitor); + + free(monitor); +} + +static void supports_full_hd_should_check_for_full_hd_support(void) +{ + static const char *monitor_without_hd = "{\n\ +\t\t\"name\": \"lame monitor\",\n\ +\t\t\"resolutions\":\t[{\n\ +\t\t\t\"width\":\t640,\n\ +\t\t\t\"height\":\t480\n\ +\t\t}]\n\ +}"; + + TEST_ASSERT(supports_full_hd(json)); + TEST_ASSERT_FALSE(supports_full_hd(monitor_without_hd)); +} + +int main(void) +{ + UNITY_BEGIN(); + + RUN_TEST(create_monitor_should_create_a_monitor); + RUN_TEST(create_monitor_with_helpers_should_create_a_monitor); + RUN_TEST(supports_full_hd_should_check_for_full_hd_support); + + return UNITY_END(); +} From f26d8f3175c2b41ba9568e9ec1c2425b401e8d0f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 30 Dec 2017 02:32:43 +0100 Subject: [PATCH 100/307] README: Add small note about CMake on Windows. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index aa345e7e..2969ba3d 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,8 @@ make make DESTDIR=$pkgdir install ``` +On Windows CMake is usually used to create a Visual Studio solution file by running it inside the Developer Command Prompt for Visual Studio, for exact steps follow the official documentation from CMake and Microsoft and use the online search engine of your choice. The descriptions of the the options above still generally apply, although not all of them work on Windows. + #### Makefile If you don't have CMake available, but still have GNU make. You can use the makefile to build cJSON: From d7e711c0de28e6ea316531a355ae2150e9a00c65 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 30 Dec 2017 21:47:28 +0100 Subject: [PATCH 101/307] README: new doc: Add links for 4th level sections --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 2969ba3d..e8903332 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,28 @@ Ultralightweight JSON parser in ANSI C. * [Usage](#usage) * [Welcome to cJSON](#welcome-to-cjson) * [Building](#building) + * [Copying the source](#copying-the-source) + * [CMake](#cmake) + * [Makefile](#makefile) * [Including cJSON](#including-cjson) * [Data Structure](#data-structure) * [Working with the data structure](#working-with-the-data-structure) + * [Basic types](#basic-types) + * [Arrays](#arrays) + * [Objects](#objects) * [Parsing JSON](#parsing-json) * [Printing JSON](#printing-json) * [Example](#example) + * [Printing](#printing) + * [Parsing](#parsing) * [Caveats](#caveats) + * [Zero Character](#zero-character) + * [Character Encoding](#character-encoding) + * [C Standard](#c-standard) + * [Floating Point Numbers](#floating-point-numbers) + * [Deep Nesting Of Arrays And Objects](#deep-nesting-of-arrays-and-objects) + * [Thread Safety](#thread-safety) + * [Case Sensitivity](#case-sensitivity) * [Enjoy cJSON!](#enjoy-cjson) ## License From 1e953636389224bf3be77f7dd1671a751c76cb4d Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 31 Dec 2017 01:24:35 +0100 Subject: [PATCH 102/307] README: Caveats: Duplicate object members --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index e8903332..01971360 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Ultralightweight JSON parser in ANSI C. * [Deep Nesting Of Arrays And Objects](#deep-nesting-of-arrays-and-objects) * [Thread Safety](#thread-safety) * [Case Sensitivity](#case-sensitivity) + * [Duplicate Object Members](#duplicate-object-members) * [Enjoy cJSON!](#enjoy-cjson) ## License @@ -517,6 +518,10 @@ However it is thread safe under the following conditions: When cJSON was originally created, it didn't follow the JSON standard and didn't make a distinction between uppercase and lowercase letters. If you want the correct, standard compliant, behavior, you need to use the `CaseSensitive` functions where available. +#### Duplicate Object Members + +cJSON supports parsing and printing JSON that contains objects that have multiple members with the same name. `cJSON_GetObjectItemCaseSensitive` however will always only return the first one. + # Enjoy cJSON! - Dave Gamble (original author) From 17b83e76e9c6f446bf15a6c1187bd1ab9157916c Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 31 Dec 2017 02:01:53 +0100 Subject: [PATCH 103/307] Update Changelog for version 1.7 --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7856838..3d1a2dbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +1.7.0 +===== +Features: +--------- +* Large rewrite of the documentation, see #215 +* Added the `cJSON_GetStringValue` function +* Added the `cJSON_CreateStringReference` function +* Added the `cJSON_CreateArrayReference` function +* Added the `cJSON_CreateObjectReference` function +* The `cJSON_Add...ToObject` macros are now functions that return a pointer to the added item, see #226 + +Fixes: +------ +* Fix a problem with `GNUInstallDirs` in the CMakeLists.txt, thanks @yangfl, see #210 +* Fix linking the tests when building as static library, see #213 +* New overrides for the CMake option `BUILD_SHARED_LIBS`, see #207 + +Other Changes: +-------------- +* Readme: Explain how to include cJSON, see #211 +* Removed some trailing spaces in the code, thanks @yangfl, see#212 +* Updated [Unity](https://github.com/ThrowTheSwitch/Unity) and [json-patch-tests](https://github.com/json-patch/json-patch-tests) + 1.6.0 ===== Features: From 13a2d337a8a308b738728008ec12cda876bd1c2b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 31 Dec 2017 02:03:40 +0100 Subject: [PATCH 104/307] Update version number to 1.7 --- CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 97f9cfe6..8b3c33cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ project(cJSON C) include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) -set(PROJECT_VERSION_MINOR 6) +set(PROJECT_VERSION_MINOR 7) set(PROJECT_VERSION_PATCH 0) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) diff --git a/Makefile b/Makefile index 2d472078..75c12c9d 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.6.0 +LIBVERSION = 1.7.0 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index e2272e66..2f747ea9 100644 --- a/cJSON.c +++ b/cJSON.c @@ -82,7 +82,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 6) || (CJSON_VERSION_PATCH != 0) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 0) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index c3d8c76b..770e1ef6 100644 --- a/cJSON.h +++ b/cJSON.h @@ -30,7 +30,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 -#define CJSON_VERSION_MINOR 6 +#define CJSON_VERSION_MINOR 7 #define CJSON_VERSION_PATCH 0 #include From f33fa95f3d4411bc8b9624d5ae8ecc9b22d1ff1c Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 9 Jan 2018 20:49:03 +0100 Subject: [PATCH 105/307] print: Fix default buffer size in printbuffer Thanks @liuyunbin for reporting this in #230 --- cJSON.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 2f747ea9..71ac65c1 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1087,13 +1087,15 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) { + static const size_t default_buffer_size = 256; printbuffer buffer[1]; unsigned char *printed = NULL; memset(buffer, 0, sizeof(buffer)); /* create buffer */ - buffer->buffer = (unsigned char*) hooks->allocate(256); + buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; buffer->format = format; buffer->hooks = *hooks; if (buffer->buffer == NULL) From 28d4410f42a64515290ce94688bcbbb9b2337c1f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 9 Jan 2018 20:53:33 +0100 Subject: [PATCH 106/307] print: fix: realloc was allocating too much memory Thanks @liuyunbin for reporting this in #230 --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 71ac65c1..9b6ef33b 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1113,7 +1113,7 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i /* check if reallocate is available */ if (hooks->reallocate != NULL) { - printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->length); + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); buffer->buffer = NULL; if (printed == NULL) { goto fail; From 4d84acf9266e9dc0366a01171d4b0fb1410910a2 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 9 Jan 2018 21:40:55 +0100 Subject: [PATCH 107/307] print_number: fix Off-By-One error Thanks @liuyunbin for reporting this in #230 --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 9b6ef33b..4cfc7195 100644 --- a/cJSON.c +++ b/cJSON.c @@ -512,7 +512,7 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out } /* reserve appropriate space in the output */ - output_pointer = ensure(output_buffer, (size_t)length); + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); if (output_pointer == NULL) { return false; From b60b5d37444c629b67782d38c4c75a40db242db7 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 9 Jan 2018 21:59:42 +0100 Subject: [PATCH 108/307] Update version to 1.7.1 --- CHANGELOG.md | 7 +++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d1a2dbf..e5bcdb63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +1.7.1 +===== +Fixes: +------ +* Fixed an Off-By-One error that could lead to an out of bounds write. Thanks @liuyunbin for reporting (see #230) +* Fixed two errors with buffered printing. Thanks @liuyunbin for reporting (see #230) + 1.7.0 ===== Features: diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b3c33cb..15e440d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 0) +set(PROJECT_VERSION_PATCH 1) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 75c12c9d..941e561e 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.0 +LIBVERSION = 1.7.1 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 4cfc7195..d20c676e 100644 --- a/cJSON.c +++ b/cJSON.c @@ -82,7 +82,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 0) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 1) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 770e1ef6..52101e11 100644 --- a/cJSON.h +++ b/cJSON.h @@ -31,7 +31,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 0 +#define CJSON_VERSION_PATCH 1 #include From f47271f4556c6b4fa2f6cd8e50806bb1d7f35237 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 6 Feb 2018 11:24:03 +0100 Subject: [PATCH 109/307] Fix pkgconfig and installation. Thanks @zeerd for reporting CMAKE_INSTALL_FULL_... needs to be used. --- CMakeLists.txt | 28 +++++++++++----------------- library_config/cJSONConfig.cmake.in | 4 ++-- library_config/libcjson.pc.in | 7 +++---- library_config/libcjson_utils.pc.in | 7 +++---- 4 files changed, 19 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 15e440d1..695d8eec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,12 +107,6 @@ endforeach() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${supported_compiler_flags}") -#variables for pkg-config -set(prefix "${CMAKE_INSTALL_PREFIX}") -set(libdir "${CMAKE_INSTALL_LIBDIR}") -set(version "${PROJECT_VERSION}") -set(includedir "${CMAKE_INSTALL_INCLUDEDIR}") - option(BUILD_SHARED_LIBS "Build shared libraries" ON) option(ENABLE_TARGET_EXPORT "Enable exporting of CMake targets. Disable when it causes problems!" ON) @@ -149,15 +143,15 @@ endif() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" @ONLY) -install(FILES cJSON.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cjson") -install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") -install(TARGETS "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" EXPORT "${CJSON_LIB}") +install(FILES cJSON.h DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/cjson") +install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig") +install(TARGETS "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" EXPORT "${CJSON_LIB}") if (BUILD_SHARED_AND_STATIC_LIBS) - install(TARGETS "${CJSON_LIB}-static" DESTINATION "${CMAKE_INSTALL_LIBDIR}") + install(TARGETS "${CJSON_LIB}-static" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}") endif() if(ENABLE_TARGET_EXPORT) # export library information for CMake projects - install(EXPORT "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON") + install(EXPORT "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON") endif() set_target_properties("${CJSON_LIB}" @@ -188,15 +182,15 @@ if(ENABLE_CJSON_UTILS) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson_utils.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" @ONLY) - install(TARGETS "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" EXPORT "${CJSON_UTILS_LIB}") + install(TARGETS "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" EXPORT "${CJSON_UTILS_LIB}") if (BUILD_SHARED_AND_STATIC_LIBS) - install(TARGETS "${CJSON_UTILS_LIB}-static" DESTINATION "${CMAKE_INSTALL_LIBDIR}") + install(TARGETS "${CJSON_UTILS_LIB}-static" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}") endif() - install(FILES cJSON_Utils.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cjson") - install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + install(FILES cJSON_Utils.h DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/cjson") + install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig") if(ENABLE_TARGET_EXPORT) # export library information for CMake projects - install(EXPORT "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON") + install(EXPORT "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON") endif() set_target_properties("${CJSON_UTILS_LIB}" @@ -216,7 +210,7 @@ configure_file( # Install package config files install(FILES ${PROJECT_BINARY_DIR}/cJSONConfig.cmake ${PROJECT_BINARY_DIR}/cJSONConfigVersion.cmake - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON") + DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON") option(ENABLE_CJSON_TEST "Enable building cJSON test" ON) if(ENABLE_CJSON_TEST) diff --git a/library_config/cJSONConfig.cmake.in b/library_config/cJSONConfig.cmake.in index 67e83252..909f7a9a 100644 --- a/library_config/cJSONConfig.cmake.in +++ b/library_config/cJSONConfig.cmake.in @@ -2,8 +2,8 @@ set(CJSON_UTILS_FOUND @ENABLE_CJSON_UTILS@) # The include directories used by cJSON -set(CJSON_INCLUDE_DIRS "@prefix@/@includedir@") -set(CJSON_INCLUDE_DIR "@prefix@/@includedir@") +set(CJSON_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@") +set(CJSON_INCLUDE_DIR "@CMAKE_INSTALL_FULL_INCLUDEDIR@") get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) diff --git a/library_config/libcjson.pc.in b/library_config/libcjson.pc.in index b3a5b405..7e616bbd 100644 --- a/library_config/libcjson.pc.in +++ b/library_config/libcjson.pc.in @@ -1,9 +1,8 @@ -prefix=@prefix@ -libdir=${prefix}/@libdir@ -includedir=${prefix}/@includedir@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: libcjson -Version: @version@ +Version: @PROJECT_VERSION@ Description: Ultralightweight JSON parser in ANSI C URL: https://github.com/DaveGamble/cJSON Libs: -L${libdir} -lcjson diff --git a/library_config/libcjson_utils.pc.in b/library_config/libcjson_utils.pc.in index 174ab600..830259fa 100644 --- a/library_config/libcjson_utils.pc.in +++ b/library_config/libcjson_utils.pc.in @@ -1,9 +1,8 @@ -prefix=@prefix@ -libdir=${prefix}/@libdir@ -includedir=${prefix}/@includedir@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: libcjson_utils -Version: @version@ +Version: @PROJECT_VERSION@ Description: An implementation of JSON Pointer, Patch and Merge Patch based on cJSON. URL: https://github.com/DaveGamble/cJSON Libs: -L${libdir} -lcjson_utils From 27caa364b0d05d4f2dbd51f2a3ff8be58d35cae1 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 6 Feb 2018 11:38:41 +0100 Subject: [PATCH 110/307] Release version 1.7.2 --- CHANGELOG.md | 6 ++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5bcdb63..f6bb718d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +1.7.2 +===== +Fixes: +------ +* Fix the use of GNUInstallDirs variables and the pkgconfig file. Thanks @zeerd for reporting (see #240) + 1.7.1 ===== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 695d8eec..4ed19bee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 1) +set(PROJECT_VERSION_PATCH 2) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 941e561e..7a53bd50 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.1 +LIBVERSION = 1.7.2 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index d20c676e..67fda56a 100644 --- a/cJSON.c +++ b/cJSON.c @@ -82,7 +82,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 1) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 2) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 52101e11..ac114645 100644 --- a/cJSON.h +++ b/cJSON.h @@ -31,7 +31,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 1 +#define CJSON_VERSION_PATCH 2 #include From d514bb866ef9d7d8ab394fbce5168c3b45f7c504 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 7 Feb 2018 19:36:59 +0100 Subject: [PATCH 111/307] Fix #241, potential double free --- cJSON.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index 67fda56a..e8da3d3d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1311,10 +1311,6 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp size_t raw_length = 0; if (item->valuestring == NULL) { - if (!output_buffer->noalloc) - { - output_buffer->hooks.deallocate(output_buffer->buffer); - } return false; } From a559eac472652e8098939af8828ff59eda3a66ae Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Wed, 7 Feb 2018 21:16:35 +0100 Subject: [PATCH 112/307] Release version 1.7.3 --- CHANGELOG.md | 6 ++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6bb718d..001269bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +1.7.2 +===== +Fixes: +------ +* Fix potential double free, thanks @projectgus for reporting (see #241) + 1.7.2 ===== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ed19bee..774280e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 2) +set(PROJECT_VERSION_PATCH 3) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 7a53bd50..1b4552b5 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.2 +LIBVERSION = 1.7.3 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index e8da3d3d..3dcde3d2 100644 --- a/cJSON.c +++ b/cJSON.c @@ -82,7 +82,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 2) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 3) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index ac114645..b6937b37 100644 --- a/cJSON.h +++ b/cJSON.h @@ -31,7 +31,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 2 +#define CJSON_VERSION_PATCH 3 #include From 22a7d04fa004462e0dca35c3cc7809bea38e65f9 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 2 Mar 2018 19:49:55 +0100 Subject: [PATCH 113/307] add_item_to_object: Fix use-after-free when string is aliased If the `string` property of the item that is added is an alias to the `string` parameter of `add_item_to_object`, and `constant` is false, `cJSON_strdup` would access the string after it has been freed. Thanks @hhallen for reporting this in #248. --- cJSON.c | 27 ++++++++++++++++----------- tests/misc_tests.c | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/cJSON.c b/cJSON.c index 3dcde3d2..cf48ac9e 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1895,33 +1895,38 @@ 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 (!(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; + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; } else { - char *key = (char*)cJSON_strdup((const unsigned char*)string, hooks); - if (key == NULL) + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) { return false; } - item->string = key; - item->type &= ~cJSON_StringIsConst; + new_type = item->type & ~cJSON_StringIsConst; } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + 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 a900e8fc..a0b4f7eb 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(); } From 5da9edc8b145d4f335267a23076c63a90a78b672 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 2 Mar 2018 19:57:36 +0100 Subject: [PATCH 114/307] Release version 1.7.4 --- CHANGELOG.md | 8 +++++++- CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 001269bb..b40c8957 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ -1.7.2 +1.7.4 +===== +Fixes: +------ +* Fix potential use after free if the `string` parameter to `cJSON_AddItemToObject` is an alias of the `string` property of the object that is added (#248). Thanks @hhallen for reporting. + +1.7.3 ===== Fixes: ------ diff --git a/CMakeLists.txt b/CMakeLists.txt index 774280e1..41b8b291 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 3) +set(PROJECT_VERSION_PATCH 4) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 1b4552b5..01ee7540 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.3 +LIBVERSION = 1.7.4 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index cf48ac9e..b4fc727d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -82,7 +82,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 3) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 4) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index b6937b37..4dc1cfb7 100644 --- a/cJSON.h +++ b/cJSON.h @@ -31,7 +31,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 3 +#define CJSON_VERSION_PATCH 4 #include From d26a42af8d9af7931c0e47055240a768a6e4139f Mon Sep 17 00:00:00 2001 From: Bob Kocisko Date: Tue, 20 Mar 2018 12:58:25 -0400 Subject: [PATCH 115/307] json patch: adding to a subfield of a non-object now fails as expected --- cJSON_Utils.c | 6 ++++++ tests/json-patch-tests/cjson-utils-tests.json | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index b83cfcd4..0d199f88 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -988,6 +988,12 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_ cJSON_AddItemToObject(parent, (char*)child_pointer, value); value = NULL; } + else /* parent is not an object */ + { + /* Couldn't find object to add to. */ + status = 9; + goto cleanup; + } cleanup: if (value != NULL) diff --git a/tests/json-patch-tests/cjson-utils-tests.json b/tests/json-patch-tests/cjson-utils-tests.json index 80377733..28a5e307 100644 --- a/tests/json-patch-tests/cjson-utils-tests.json +++ b/tests/json-patch-tests/cjson-utils-tests.json @@ -80,5 +80,12 @@ "doc": { "foo": ["bar"] }, "patch": [ { "op": "add", "path": "/foo/-", "value": ["abc", "def"] }], "expected": {"foo": ["bar", ["abc", "def"]] } - } + }, + + { + "comment": "15", + "doc": {"foo": {"bar": 1}}, + "patch": [{"op": "add", "path": "/foo/bar/baz", "value": "5"}], + "error": "attempting to add to subfield of non-object" + } ] From 5d50f4efe1f82f1f1210c4900a8cbf5356630b6c Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 22 Mar 2018 20:28:30 +0100 Subject: [PATCH 116/307] Contributors: Thank all the non-code contributors --- CONTRIBUTORS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 9353be67..6f7997f5 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -42,3 +42,5 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB) * [yangfl](https://github.com/yangfl) And probably more people on [SourceForge](https://sourceforge.net/p/cjson/bugs/search/?q=status%3Aclosed-rejected+or+status%3Aclosed-out-of-date+or+status%3Awont-fix+or+status%3Aclosed-fixed+or+status%3Aclosed&page=0) + +Also thanks to all the people who reported bugs and suggested new features. From 2336a0348d2613ed580d25f90bd596db12560bfd Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 22 Mar 2018 20:28:54 +0100 Subject: [PATCH 117/307] Contributors: Add Bob Kocisko --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 6f7997f5..302ad4df 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -7,6 +7,7 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB) * [Ajay Bhargav](https://github.com/ajaybhargav) * [Alper Akcan](https://github.com/alperakcan) * [Anton Sergeev](https://github.com/anton-sergeev) +* [Bob Kocisko](https://github.com/bobkocisko) * [Christian Schulze](https://github.com/ChristianSch) * [Casperinous](https://github.com/Casperinous) * [Debora Grosse](https://github.com/DeboraG) From 0e0c463491004d0e69aad1368450e92d6647dff3 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 22 Mar 2018 20:29:17 +0100 Subject: [PATCH 118/307] Release version 1.7.5 --- CHANGELOG.md | 6 ++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b40c8957..17d0e93f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +1.7.5 +===== +Fixes: +------ +* Fix a bug in the JSON Patch implementation of `cJSON Utils` (see #251), thanks @bobkocisko. + 1.7.4 ===== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 41b8b291..09039f62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 4) +set(PROJECT_VERSION_PATCH 5) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 01ee7540..10222fac 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.4 +LIBVERSION = 1.7.5 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index b4fc727d..7e71ea9e 100644 --- a/cJSON.c +++ b/cJSON.c @@ -82,7 +82,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 4) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 5) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 4dc1cfb7..a9c68fa2 100644 --- a/cJSON.h +++ b/cJSON.h @@ -31,7 +31,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 4 +#define CJSON_VERSION_PATCH 5 #include From e6869c2e0370b7139819521b5c4e1a9ef0bf392a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 13 Apr 2018 10:32:29 +0800 Subject: [PATCH 119/307] cJSON_Utils.h: Add include guards and extern C for C++ --- cJSON_Utils.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cJSON_Utils.h b/cJSON_Utils.h index 03ec10c9..a970c650 100644 --- a/cJSON_Utils.h +++ b/cJSON_Utils.h @@ -20,6 +20,14 @@ THE SOFTWARE. */ +#ifndef cJSON_Utils__h +#define cJSON_Utils__h + +#ifdef __cplusplus +extern "C" +{ +#endif + #include "cJSON.h" /* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */ @@ -72,3 +80,9 @@ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const obje /* Sorts the members of the object into alphabetical order. */ CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object); CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object); + +#ifdef __cplusplus +} +#endif + +#endif From ed8fefc9ca8fe0c8c21001ad5dc27daee8801e1c Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 13 Apr 2018 11:57:49 +0800 Subject: [PATCH 120/307] Makefile: Fix #252, put soname in the ELF file --- Makefile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 10222fac..17ddce1e 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,9 @@ LIBVERSION = 1.7.5 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 +CJSON_SO_LDFLAG=-Wl,-soname=$(CJSON_LIBNAME).so.$(CJSON_SOVERSION) +UTILS_SO_LDFLAG=-Wl,-soname=$(UTILS_LIBNAME).so.$(UTILS_SOVERSION) + PREFIX ?= /usr/local INCLUDE_PATH ?= include/cjson LIBRARY_PATH ?= lib @@ -42,6 +45,8 @@ STATIC = a ## create dynamic (shared) library on Darwin (base OS for MacOSX and IOS) ifeq (Darwin, $(uname)) SHARED = dylib + CJSON_SO_LDFLAG = "" + UTILS_SO_LDFLAG = "" endif #cJSON library names @@ -90,10 +95,10 @@ $(UTILS_STATIC): $(UTILS_OBJ) #shared libraries .so.1.0.0 #cJSON $(CJSON_SHARED_VERSION): $(CJSON_OBJ) - $(CC) -shared -o $@ $< $(LDFLAGS) + $(CC) -shared -o $@ $< $(CJSON_SO_LDFLAG) $(LDFLAGS) #cJSON_Utils $(UTILS_SHARED_VERSION): $(UTILS_OBJ) - $(CC) -shared -o $@ $< $(LDFLAGS) + $(CC) -shared -o $@ $< $(UTILS_SO_LDFLAG) $(LDFLAGS) #objects #cJSON From 7996a4a2eeee6339703259e799c42814ccf79daa Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 13 Apr 2018 12:12:26 +0800 Subject: [PATCH 121/307] Readme: Deprecate the Makefile --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 01971360..c6b788f9 100644 --- a/README.md +++ b/README.md @@ -127,9 +127,11 @@ make DESTDIR=$pkgdir install On Windows CMake is usually used to create a Visual Studio solution file by running it inside the Developer Command Prompt for Visual Studio, for exact steps follow the official documentation from CMake and Microsoft and use the online search engine of your choice. The descriptions of the the options above still generally apply, although not all of them work on Windows. #### Makefile +**NOTE:** This Method is deprecated. Use CMake if at all possible. Makefile support is limited to fixing bugs. + If you don't have CMake available, but still have GNU make. You can use the makefile to build cJSON: -Run this command in the directory with the source code and it will automatically compile static and shared libraries and a little test program. +Run this command in the directory with the source code and it will automatically compile static and shared libraries and a little test program (not the full test suite). ``` make all From cbc05de76fbd4dfff17b5626d5cfe9ec922b1f4a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 13 Apr 2018 12:32:30 +0800 Subject: [PATCH 122/307] Release version 1.7.6 --- CHANGELOG.md | 11 +++++++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17d0e93f..b7b53e36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +1.7.6 +===== +Fixes: +------ +* Add `SONAME` to the ELF files built by the Makefile (see #252), thanks @YanhaoMo for reporting +* Add include guards and `extern "C"` to `cJSON_Utils.h` (see #256), thanks @daschfg for reporting + +Other changes: +-------------- +* Mark the Makefile as deprecated in the README. + 1.7.5 ===== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 09039f62..fc8c042e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 5) +set(PROJECT_VERSION_PATCH 6) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 17ddce1e..0b302a07 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.5 +LIBVERSION = 1.7.6 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 7e71ea9e..15d3fef4 100644 --- a/cJSON.c +++ b/cJSON.c @@ -82,7 +82,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 5) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 6) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index a9c68fa2..15eda75f 100644 --- a/cJSON.h +++ b/cJSON.h @@ -31,7 +31,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 5 +#define CJSON_VERSION_PATCH 6 #include From 3349978268ea8f8ace9bde1cb30bce922513fbe1 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 26 Apr 2018 23:58:51 +0200 Subject: [PATCH 123/307] cJSON.c: Remove unnecessary include of float.h, fix #259 --- cJSON.c | 1 - 1 file changed, 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 15d3fef4..8cda3901 100644 --- a/cJSON.c +++ b/cJSON.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include From 529ec06abbc0aebac4ef719257d7b03efa643d64 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 29 Apr 2018 09:20:08 +0200 Subject: [PATCH 124/307] Makefile: Fix #263, use $(CC) instead of 'gcc' for detecting the version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0b302a07..c0edd4a4 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ INSTALL ?= cp -a # validate gcc version for use fstack-protector-strong MIN_GCC_VERSION = "4.9" -GCC_VERSION := "`gcc -dumpversion`" +GCC_VERSION := "`$(CC) -dumpversion`" IS_GCC_ABOVE_MIN_VERSION := $(shell expr "$(GCC_VERSION)" ">=" "$(MIN_GCC_VERSION)") ifeq "$(IS_GCC_ABOVE_MIN_VERSION)" "1" CFLAGS += -fstack-protector-strong From 0d5ecc11b6af3fc8869b80520804e83ec44d8487 Mon Sep 17 00:00:00 2001 From: Zhao Zhixu Date: Tue, 8 May 2018 22:45:14 +0800 Subject: [PATCH 125/307] fix typo --- cJSON.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.h b/cJSON.h index 15eda75f..b374fe49 100644 --- a/cJSON.h +++ b/cJSON.h @@ -156,7 +156,7 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); /* Returns the number of items in an array (or object). */ CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); -/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ +/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); /* Get item "string" from object. Case insensitive. */ CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); From 787d651e8131c6394c6ff844f108e1a53012949f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Tue, 8 May 2018 21:33:33 +0200 Subject: [PATCH 126/307] Contributors: Add Zhao Zhixu --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 302ad4df..434a90d7 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -41,6 +41,7 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB) * [Stephan Gatzka](https://github.com/gatzka) * [Weston Schmidt](https://github.com/schmidtw) * [yangfl](https://github.com/yangfl) +* [Zhao Zhixu](https://github.com/zhaozhixu) And probably more people on [SourceForge](https://sourceforge.net/p/cjson/bugs/search/?q=status%3Aclosed-rejected+or+status%3Aclosed-out-of-date+or+status%3Awont-fix+or+status%3Aclosed-fixed+or+status%3Aclosed&page=0) From af5b4911de6e00306370460d978ac1654d3aeaec Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 21 May 2018 22:00:07 +0200 Subject: [PATCH 127/307] Fix memory leak if realloc returns NULL Thanks @AlfieDeng for reporting --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 8cda3901..537e21a6 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1113,10 +1113,10 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i if (hooks->reallocate != NULL) { printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); - buffer->buffer = NULL; if (printed == NULL) { goto fail; } + buffer->buffer = NULL; } else /* otherwise copy the JSON over to a new buffer */ { From 86234db0959e7c1533948d825335a14e0dfabad5 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 21 May 2018 22:08:21 +0200 Subject: [PATCH 128/307] Release cJSON v1.7.7 --- CHANGELOG.md | 7 +++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7b53e36..8d00cbb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +1.7.7 +===== +Fixes: +------ +* Fix a memory leak when realloc fails (see #267), thanks @AlfieDeng for reporting +* Fix a typo in the header file (see #266), thanks @zhaozhixu + 1.7.6 ===== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index fc8c042e..b347ac91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 6) +set(PROJECT_VERSION_PATCH 7) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index c0edd4a4..456b13a3 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.6 +LIBVERSION = 1.7.7 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 537e21a6..cbdec413 100644 --- a/cJSON.c +++ b/cJSON.c @@ -81,7 +81,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 6) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 7) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index b374fe49..6e0bde93 100644 --- a/cJSON.h +++ b/cJSON.h @@ -31,7 +31,7 @@ extern "C" /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 6 +#define CJSON_VERSION_PATCH 7 #include From f32703a7a1990b6b7c97d14a8ef6818badd2d835 Mon Sep 17 00:00:00 2001 From: Zach Hindes Date: Wed, 29 Aug 2018 16:13:59 -0500 Subject: [PATCH 129/307] Support default __stdcall calling convention (/Gz) on Windows --- cJSON.c | 12 +++---- cJSON.h | 98 +++++++++++++++++++++++++++++++-------------------------- test.c | 2 +- 3 files changed, 60 insertions(+), 52 deletions(-) diff --git a/cJSON.c b/cJSON.c index cbdec413..5c4cf661 100644 --- a/cJSON.c +++ b/cJSON.c @@ -119,22 +119,22 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned typedef struct internal_hooks { - void *(*allocate)(size_t size); - void (*deallocate)(void *pointer); - void *(*reallocate)(void *pointer, size_t size); + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); } internal_hooks; #if defined(_MSC_VER) /* work around MSVC error C2322: '...' address of dillimport '...' is not static */ -static void *internal_malloc(size_t size) +static void * CJSON_CDECL internal_malloc(size_t size) { return malloc(size); } -static void internal_free(void *pointer) +static void CJSON_CDECL internal_free(void *pointer) { free(pointer); } -static void *internal_realloc(void *pointer, size_t size) +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) { return realloc(pointer, size); } diff --git a/cJSON.h b/cJSON.h index 6e0bde93..18210c82 100644 --- a/cJSON.h +++ b/cJSON.h @@ -28,6 +28,56 @@ extern "C" { #endif +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 @@ -74,55 +124,13 @@ typedef struct cJSON typedef struct cJSON_Hooks { - void *(*malloc_fn)(size_t sz); - void (*free_fn)(void *ptr); + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); } cJSON_Hooks; typedef int cJSON_bool; -#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) -#define __WINDOWS__ -#endif -#ifdef __WINDOWS__ - -/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options: - -CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols -CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) -CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol - -For *nix builds that support visibility attribute, you can define similar behavior by - -setting default visibility to hidden by adding --fvisibility=hidden (for gcc) -or --xldscope=hidden (for sun cc) -to CFLAGS - -then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does - -*/ - -/* export symbols by default, this is necessary for copy pasting the C and header file */ -#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) -#define CJSON_EXPORT_SYMBOLS -#endif - -#if defined(CJSON_HIDE_SYMBOLS) -#define CJSON_PUBLIC(type) type __stdcall -#elif defined(CJSON_EXPORT_SYMBOLS) -#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall -#elif defined(CJSON_IMPORT_SYMBOLS) -#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall -#endif -#else /* !WIN32 */ -#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) -#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type -#else -#define CJSON_PUBLIC(type) type -#endif -#endif - /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. * This is to prevent stack overflows. */ #ifndef CJSON_NESTING_LIMIT diff --git a/test.c b/test.c index 66154e04..986fc6eb 100644 --- a/test.c +++ b/test.c @@ -256,7 +256,7 @@ static void create_objects(void) cJSON_Delete(root); } -int main(void) +int CJSON_CDECL main(void) { /* print the version */ printf("Version: %s\n", cJSON_Version()); From ad2cb5b7eabd0e4803bdb9402258f0f75c7bd507 Mon Sep 17 00:00:00 2001 From: Zach Hindes Date: Tue, 4 Sep 2018 14:25:15 -0500 Subject: [PATCH 130/307] Enable build and test on Windows --- .gitattributes | 2 ++ CMakeLists.txt | 2 ++ tests/CMakeLists.txt | 5 ++++- tests/cjson_add.c | 8 +++++++- tests/unity_setup.c | 3 +++ 5 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 .gitattributes create mode 100644 tests/unity_setup.c diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..6e5ee10e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto +/tests/inputs/* text eol=lf \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index b347ac91..c9d2db9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,8 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) /Za /sdl /W4 + /wd4001 + /D_CRT_SECURE_NO_WARNINGS ) endif() endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 79672927..6f1688db 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,5 +1,5 @@ if(ENABLE_CJSON_TEST) - add_library(unity "${CJSON_LIBRARY_TYPE}" unity/src/unity.c) + add_library(unity STATIC unity/src/unity.c) # Disable -Werror for Unity if (FLAG_SUPPORTED_Werror) @@ -72,6 +72,9 @@ if(ENABLE_CJSON_TEST) foreach(unity_test ${unity_tests}) add_executable("${unity_test}" "${unity_test}.c") + if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + target_sources(${unity_test} PRIVATE unity_setup.c) + endif() target_link_libraries("${unity_test}" "${CJSON_LIB}" unity) if(MEMORYCHECK_COMMAND) add_test(NAME "${unity_test}" diff --git a/tests/cjson_add.c b/tests/cjson_add.c index 01668a94..eb9def20 100644 --- a/tests/cjson_add.c +++ b/tests/cjson_add.c @@ -34,9 +34,15 @@ static void *failing_malloc(size_t size) return NULL; } +/* work around MSVC error C2322: '...' address of dillimport '...' is not static */ +static void CJSON_CDECL normal_free(void *pointer) +{ + free(pointer); +} + static cJSON_Hooks failing_hooks = { failing_malloc, - free + normal_free }; static void cjson_add_null_should_add_null(void) diff --git a/tests/unity_setup.c b/tests/unity_setup.c new file mode 100644 index 00000000..99b6897f --- /dev/null +++ b/tests/unity_setup.c @@ -0,0 +1,3 @@ +// msvc doesn't support weak-linking, so we need to define these functions. +void setUp(void) { } +void tearDown(void) { } \ No newline at end of file From f25b8448e47360a807b4b5fae3a84092c84f1468 Mon Sep 17 00:00:00 2001 From: Zach Hindes Date: Wed, 12 Sep 2018 15:32:30 -0500 Subject: [PATCH 131/307] Support default __stdcall calling convention on tests as well --- CMakeLists.txt | 2 ++ tests/cjson_add.c | 4 ++-- tests/compare_tests.c | 2 +- tests/misc_tests.c | 4 ++-- tests/parse_array.c | 2 +- tests/parse_examples.c | 2 +- tests/parse_hex4.c | 2 +- tests/parse_number.c | 2 +- tests/parse_object.c | 2 +- tests/parse_string.c | 2 +- tests/parse_value.c | 2 +- tests/parse_with_opts.c | 2 +- tests/print_array.c | 2 +- tests/print_number.c | 2 +- tests/print_object.c | 2 +- tests/print_string.c | 2 +- tests/print_value.c | 2 +- tests/readme_examples.c | 2 +- 18 files changed, 21 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9d2db9d..00bf7711 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,8 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) -Wswitch-enum ) elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + # Disable warning c4001 - nonstandard extension 'single line comment' was used + # Define _CRT_SECURE_NO_WARNINGS to disable deprecation warnings for "insecure" C library functions list(APPEND custom_compiler_flags /GS /Za diff --git a/tests/cjson_add.c b/tests/cjson_add.c index eb9def20..00ffc349 100644 --- a/tests/cjson_add.c +++ b/tests/cjson_add.c @@ -28,7 +28,7 @@ #include "unity/src/unity.h" #include "common.h" -static void *failing_malloc(size_t size) +static void * CJSON_CDECL failing_malloc(size_t size) { (void)size; return NULL; @@ -378,7 +378,7 @@ static void cjson_add_array_should_fail_on_allocation_failure(void) cJSON_Delete(root); } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); diff --git a/tests/compare_tests.c b/tests/compare_tests.c index 63b6d4a0..307d0e82 100644 --- a/tests/compare_tests.c +++ b/tests/compare_tests.c @@ -186,7 +186,7 @@ static void cjson_compare_should_compare_objects(void) false)) } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index a0b4f7eb..f42772a7 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -410,7 +410,7 @@ static void cjson_functions_shouldnt_crash_with_null_pointers(void) cJSON_Delete(item); } -static void *failing_realloc(void *pointer, size_t size) +static void * CJSON_CDECL failing_realloc(void *pointer, size_t size) { (void)size; (void)pointer; @@ -527,7 +527,7 @@ static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_al cJSON_Delete(object); } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); diff --git a/tests/parse_array.c b/tests/parse_array.c index 69e0f411..dfaae29b 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -152,7 +152,7 @@ static void parse_array_should_not_parse_non_arrays(void) assert_not_array("\"[]hello world!\n\""); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ memset(item, 0, sizeof(cJSON)); diff --git a/tests/parse_examples.c b/tests/parse_examples.c index 76215bbc..3aab77fe 100644 --- a/tests/parse_examples.c +++ b/tests/parse_examples.c @@ -195,7 +195,7 @@ static void test12_should_not_be_parsed(void) } } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); RUN_TEST(file_test1_should_be_parsed_and_printed); diff --git a/tests/parse_hex4.c b/tests/parse_hex4.c index 7115cbae..83cbe658 100644 --- a/tests/parse_hex4.c +++ b/tests/parse_hex4.c @@ -64,7 +64,7 @@ static void parse_hex4_should_parse_mixed_case(void) TEST_ASSERT_EQUAL_INT(0xBEEF, parse_hex4((const unsigned char*)"BEEF")); } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); RUN_TEST(parse_hex4_should_parse_all_combinations); diff --git a/tests/parse_number.c b/tests/parse_number.c index f499ab65..4cb72ec2 100644 --- a/tests/parse_number.c +++ b/tests/parse_number.c @@ -96,7 +96,7 @@ static void parse_number_should_parse_negative_reals(void) assert_parse_number("-123e-128", 0, -123e-128); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ memset(item, 0, sizeof(cJSON)); diff --git a/tests/parse_object.c b/tests/parse_object.c index 09858455..5f8e7cf1 100644 --- a/tests/parse_object.c +++ b/tests/parse_object.c @@ -162,7 +162,7 @@ static void parse_object_should_not_parse_non_objects(void) assert_not_object("\"{}hello world!\n\""); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ memset(item, 0, sizeof(cJSON)); diff --git a/tests/parse_string.c b/tests/parse_string.c index ceb1a896..ce1c138e 100644 --- a/tests/parse_string.c +++ b/tests/parse_string.c @@ -119,7 +119,7 @@ static void parse_string_should_parse_bug_94(void) reset(item); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item and error pointer */ memset(item, 0, sizeof(cJSON)); diff --git a/tests/parse_value.c b/tests/parse_value.c index 08ec3e7a..6b6b0955 100644 --- a/tests/parse_value.c +++ b/tests/parse_value.c @@ -96,7 +96,7 @@ static void parse_value_should_parse_object(void) reset(item); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ memset(item, 0, sizeof(cJSON)); diff --git a/tests/parse_with_opts.c b/tests/parse_with_opts.c index 84b69cfc..e390b92d 100644 --- a/tests/parse_with_opts.c +++ b/tests/parse_with_opts.c @@ -97,7 +97,7 @@ static void parse_with_opts_should_parse_utf8_bom(void) cJSON_Delete(without_bom); } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); diff --git a/tests/print_array.c b/tests/print_array.c index 4bee17f9..7d40f2e2 100644 --- a/tests/print_array.c +++ b/tests/print_array.c @@ -87,7 +87,7 @@ static void print_array_should_print_arrays_with_multiple_elements(void) assert_print_array("[1, null, true, false, [], \"hello\", {\n\t}]", "[1,null,true,false,[],\"hello\",{}]"); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ UNITY_BEGIN(); diff --git a/tests/print_number.c b/tests/print_number.c index 5ebb3489..f2385f3b 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -89,7 +89,7 @@ static void print_number_should_print_non_number(void) /* assert_print_number("null", -INFTY); */ } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ UNITY_BEGIN(); diff --git a/tests/print_object.c b/tests/print_object.c index 70bbb43c..3ed0bfed 100644 --- a/tests/print_object.c +++ b/tests/print_object.c @@ -88,7 +88,7 @@ static void print_object_should_print_objects_with_multiple_elements(void) assert_print_object("{\n\t\"one\":\t1,\n\t\"NULL\":\tnull,\n\t\"TRUE\":\ttrue,\n\t\"FALSE\":\tfalse,\n\t\"array\":\t[],\n\t\"world\":\t\"hello\",\n\t\"object\":\t{\n\t}\n}", "{\"one\":1,\"NULL\":null,\"TRUE\":true,\"FALSE\":false,\"array\":[],\"world\":\"hello\",\"object\":{}}"); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ UNITY_BEGIN(); diff --git a/tests/print_string.c b/tests/print_string.c index 83de1e7a..e6f5b92d 100644 --- a/tests/print_string.c +++ b/tests/print_string.c @@ -65,7 +65,7 @@ static void print_string_should_print_utf8(void) assert_print_string("\"ü猫慕\"", "ü猫慕"); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ UNITY_BEGIN(); diff --git a/tests/print_value.c b/tests/print_value.c index d5908232..b54db5b1 100644 --- a/tests/print_value.c +++ b/tests/print_value.c @@ -90,7 +90,7 @@ static void print_value_should_print_object(void) assert_print_value("{}"); } -int main(void) +int CJSON_CDECL main(void) { /* initialize cJSON item */ UNITY_BEGIN(); diff --git a/tests/readme_examples.c b/tests/readme_examples.c index f3fa4438..1ab1b139 100644 --- a/tests/readme_examples.c +++ b/tests/readme_examples.c @@ -246,7 +246,7 @@ static void supports_full_hd_should_check_for_full_hd_support(void) TEST_ASSERT_FALSE(supports_full_hd(monitor_without_hd)); } -int main(void) +int CJSON_CDECL main(void) { UNITY_BEGIN(); From d9fe34bade211088b0c8f5db4e4ac9d09cc12a92 Mon Sep 17 00:00:00 2001 From: Zach Hindes Date: Mon, 17 Sep 2018 09:10:20 -0500 Subject: [PATCH 132/307] Add newline to end of unity_setup.c --- tests/unity_setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unity_setup.c b/tests/unity_setup.c index 99b6897f..1d828b0b 100644 --- a/tests/unity_setup.c +++ b/tests/unity_setup.c @@ -1,3 +1,3 @@ // msvc doesn't support weak-linking, so we need to define these functions. void setUp(void) { } -void tearDown(void) { } \ No newline at end of file +void tearDown(void) { } From 00544a4a74a77fb91c9d76a425144c4e7fdbbd47 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 21 Sep 2018 19:26:01 +0200 Subject: [PATCH 133/307] Contributors: Add Zach Hindes --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 434a90d7..7b90507c 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -41,6 +41,7 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB) * [Stephan Gatzka](https://github.com/gatzka) * [Weston Schmidt](https://github.com/schmidtw) * [yangfl](https://github.com/yangfl) +* [Zach Hindes](https://github.com/zhindes) * [Zhao Zhixu](https://github.com/zhaozhixu) And probably more people on [SourceForge](https://sourceforge.net/p/cjson/bugs/search/?q=status%3Aclosed-rejected+or+status%3Aclosed-out-of-date+or+status%3Awont-fix+or+status%3Aclosed-fixed+or+status%3Aclosed&page=0) From ace800e444435b291725c28c7984c8b656e38c74 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 21 Sep 2018 19:28:25 +0200 Subject: [PATCH 134/307] Update changelog for 1.7.8 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d00cbb9..55965363 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +1.7.8 +===== +Fixes: +------ +* cJSON now works with the `__stdcall` calling convention on Windows, see #295, thanks @zhindes for contributing + 1.7.7 ===== Fixes: From 08103f048e5f54c8f60aaefda16761faf37114f2 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 21 Sep 2018 19:29:42 +0200 Subject: [PATCH 135/307] Release version 1.7.8 --- CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 00bf7711..f2ae7eda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 7) +set(PROJECT_VERSION_PATCH 8) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 456b13a3..3188f6a5 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.7 +LIBVERSION = 1.7.8 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 5c4cf661..5da278ee 100644 --- a/cJSON.c +++ b/cJSON.c @@ -81,7 +81,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 7) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 8) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 18210c82..8d453902 100644 --- a/cJSON.h +++ b/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 7 +#define CJSON_VERSION_PATCH 8 #include From e2162adeedc1c4fca3e2a315dca174ca80e7b644 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 11 Oct 2018 00:30:43 +0200 Subject: [PATCH 136/307] Squashed 'tests/json-patch-tests/' changes from 99264bb..9ecd703 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 9ecd703 Merge pull request #39 from mr-mixas/test-absent-from-location-for-copy-and-move-ops 66817e7 test absent 'from' location for copy and move 09dee56 Fix anonymous test 8bae8ed Fix « test should pass - no error » test 855f2a4 Fix « test should pass despite (nested) rearrangement » test 53283fc Fix « test should pass despite rearrangement » test ecf01e7 Fix « null value should be valid obj property » test 1586cdf Fix « Empty-string element » test git-subtree-dir: tests/json-patch-tests git-subtree-split: 9ecd703c08cda4864cd2d2fb580a513ec5740934 --- tests.json | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/tests.json b/tests.json index 86305c16..25540781 100644 --- a/tests.json +++ b/tests.json @@ -214,6 +214,7 @@ { "doc": {"foo": null}, "patch": [{"op": "test", "path": "/foo", "value": null}], + "expected": {"foo": null}, "comment": "null value should be valid obj property" }, { "doc": {"foo": null}, @@ -243,14 +244,17 @@ { "doc": {"foo": {"foo": 1, "bar": 2}}, "patch": [{"op": "test", "path": "/foo", "value": {"bar": 2, "foo": 1}}], + "expected": {"foo": {"foo": 1, "bar": 2}}, "comment": "test should pass despite rearrangement" }, { "doc": {"foo": [{"foo": 1, "bar": 2}]}, "patch": [{"op": "test", "path": "/foo", "value": [{"bar": 2, "foo": 1}]}], + "expected": {"foo": [{"foo": 1, "bar": 2}]}, "comment": "test should pass despite (nested) rearrangement" }, { "doc": {"foo": {"bar": [1, 2, 5, 4]}}, "patch": [{"op": "test", "path": "/foo", "value": {"bar": [1, 2, 5, 4]}}], + "expected": {"foo": {"bar": [1, 2, 5, 4]}}, "comment": "test should pass - no error" }, { "doc": {"foo": {"bar": [1, 2, 5, 4]}}, @@ -264,7 +268,8 @@ { "comment": "Empty-string element", "doc": { "": 1 }, - "patch": [{"op": "test", "path": "/", "value": 1}] }, + "patch": [{"op": "test", "path": "/", "value": 1}], + "expected": { "": 1 } }, { "doc": { "foo": ["bar", "baz"], @@ -288,8 +293,23 @@ {"op": "test", "path": "/i\\j", "value": 5}, {"op": "test", "path": "/k\"l", "value": 6}, {"op": "test", "path": "/ ", "value": 7}, - {"op": "test", "path": "/m~0n", "value": 8}] }, - + {"op": "test", "path": "/m~0n", "value": 8}], + "expected": { + "": 0, + " ": 7, + "a/b": 1, + "c%d": 2, + "e^f": 3, + "foo": [ + "bar", + "baz" + ], + "g|h": 4, + "i\\j": 5, + "k\"l": 6, + "m~n": 8 + } + }, { "comment": "Move to same location has no effect", "doc": {"foo": 1}, "patch": [{"op": "move", "from": "/foo", "path": "/foo"}], @@ -388,11 +408,21 @@ "patch": [ { "op": "copy", "path": "/-" } ], "error": "missing 'from' parameter" }, + { "comment": "missing from location to copy", + "doc": { "foo": 1 }, + "patch": [ { "op": "copy", "from": "/bar", "path": "/foo" } ], + "error": "missing 'from' location" }, + { "comment": "missing from parameter to move", "doc": { "foo": 1 }, "patch": [ { "op": "move", "path": "" } ], "error": "missing 'from' parameter" }, + { "comment": "missing from location to move", + "doc": { "foo": 1 }, + "patch": [ { "op": "move", "from": "/bar", "path": "/foo" } ], + "error": "missing 'from' location" }, + { "comment": "duplicate ops", "doc": { "foo": "bar" }, "patch": [ { "op": "add", "path": "/baz", "value": "qux", From 8e742e48690f0fb947658a8e106d0094129460a9 Mon Sep 17 00:00:00 2001 From: Benbuck Nason Date: Fri, 12 Oct 2018 14:29:59 -0700 Subject: [PATCH 137/307] Fix most of the issues reported by the Visual Studio code analysis tool. --- cJSON.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index 5da278ee..17338116 100644 --- a/cJSON.c +++ b/cJSON.c @@ -324,7 +324,7 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu { item->valueint = INT_MAX; } - else if (number <= INT_MIN) + else if (number <= (double)INT_MIN) { item->valueint = INT_MIN; } @@ -346,7 +346,7 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) { object->valueint = INT_MAX; } - else if (number <= INT_MIN) + else if (number <= (double)INT_MIN) { object->valueint = INT_MIN; } @@ -1675,7 +1675,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out update_offset(output_buffer); /* print comma if not last */ - length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0)); + length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); output_pointer = ensure(output_buffer, length + 1); if (output_pointer == NULL) { @@ -2300,7 +2300,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) { item->valueint = INT_MAX; } - else if (num <= INT_MIN) + else if (num <= (double)INT_MIN) { item->valueint = INT_MIN; } From feb05fb2fd4d7541b56ac3eded54071748bde060 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 14 Oct 2018 11:22:14 +0200 Subject: [PATCH 138/307] Add Benbuck Nason to the list of contributors --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 7b90507c..10940b89 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -7,6 +7,7 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB) * [Ajay Bhargav](https://github.com/ajaybhargav) * [Alper Akcan](https://github.com/alperakcan) * [Anton Sergeev](https://github.com/anton-sergeev) +* [Benbuck Nason](https://github.com/bnason-nf) * [Bob Kocisko](https://github.com/bobkocisko) * [Christian Schulze](https://github.com/ChristianSch) * [Casperinous](https://github.com/Casperinous) From a3fadd44d1392fd945f62b23078875a5f39c7fd4 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 14 Oct 2018 11:51:56 +0200 Subject: [PATCH 139/307] Add .editorconfig --- .editorconfig | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..befb2c20 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +root = true + + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[Makefile] +indent_style = tab +indent_size = unset + +# ignore external repositories and test inputs +[tests/{unity,json-patch-tests,inputs}/*] +indent_style = unset +indent_size = unset +end_of_line = unset +charset = unset +trim_trailing_whitespace = unset +insert_final_newline = unset From 49170247413232d3cfa489fb1209037e697ced08 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 14 Oct 2018 11:52:19 +0200 Subject: [PATCH 140/307] Makefile: Fix indentation --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3188f6a5..2921ed74 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ STATIC = a ifeq (Darwin, $(uname)) SHARED = dylib CJSON_SO_LDFLAG = "" - UTILS_SO_LDFLAG = "" + UTILS_SO_LDFLAG = "" endif #cJSON library names From 2c914c073d71701b596fa58a84529712a0bd1eeb Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 14 Oct 2018 11:52:41 +0200 Subject: [PATCH 141/307] Gitignore: Ignore CLion directories --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e2e312b5..58edf92c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ libcjson.so.* libcjson_utils.so.* *.orig .vscode +.idea +cmake-build-debug From cb1df2f88c0d335e031ade0d52fd6a59528c622f Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 3 Dec 2018 23:07:36 +0100 Subject: [PATCH 142/307] README: Add note about needing to free print results in examples --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c6b788f9..3b39c854 100644 --- a/README.md +++ b/README.md @@ -298,6 +298,7 @@ In this example we want to build and parse the following JSON: Let's build the above JSON and print it to a string: ```c //create a monitor with a list of supported resolutions +//NOTE: Returns a heap allocated string, you are required to free it after use. char* create_monitor(void) { const unsigned int resolution_numbers[3][2] = { @@ -373,6 +374,7 @@ end: Alternatively we can use the `cJSON_Add...ToObject` helper functions to make our lifes a little easier: ```c +//NOTE: Returns a heap allocated string, you are required to free it after use. char *create_monitor_with_helpers(void) { const unsigned int resolution_numbers[3][2] = { From eaec82c3c557401a43e4b4ea5763b06830d7c362 Mon Sep 17 00:00:00 2001 From: yuta-oxo <13583684+yuta-oxo@users.noreply.github.com> Date: Wed, 12 Dec 2018 15:09:53 +0900 Subject: [PATCH 143/307] fix bug: sort_list() returns strange results --- cJSON_Utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 0d199f88..f0f9094d 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -510,7 +510,7 @@ static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive) while ((first != NULL) && (second != NULL)) { cJSON *smaller = NULL; - if (compare_strings((unsigned char*)first->string, (unsigned char*)second->string, false) < 0) + if (compare_strings((unsigned char*)first->string, (unsigned char*)second->string, case_sensitive) < 0) { smaller = first; } From be749d7efa7c9021da746e685bd6dec79f9dd99b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 16 Dec 2018 11:06:40 +0100 Subject: [PATCH 144/307] Fix crash of cJSON_GetObjectItemCaseSensitive when calling it on arrays --- cJSON.c | 6 +++++- tests/misc_tests.c | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 17338116..c9c5b61f 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1781,7 +1781,7 @@ static cJSON *get_object_item(const cJSON * const object, const char * const nam current_element = object->child; if (case_sensitive) { - while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) + while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) { current_element = current_element->next; } @@ -1794,6 +1794,10 @@ static cJSON *get_object_item(const cJSON * const object, const char * const nam } } + if ((current_element == NULL) || (current_element->string == NULL)) { + return NULL; + } + return current_element; } diff --git a/tests/misc_tests.c b/tests/misc_tests.c index f42772a7..1635fa30 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -127,6 +127,28 @@ static void cjson_get_object_item_case_sensitive_should_get_object_items(void) cJSON_Delete(item); } +static void cjson_get_object_item_should_not_crash_with_array(void) { + cJSON *array = NULL; + cJSON *found = NULL; + array = cJSON_Parse("[1]"); + + found = cJSON_GetObjectItem(array, "name"); + TEST_ASSERT_NULL(found); + + cJSON_Delete(array); +} + +static void cjson_get_object_item_case_sensitive_should_not_crash_with_array(void) { + cJSON *array = NULL; + cJSON *found = NULL; + array = cJSON_Parse("[1]"); + + found = cJSON_GetObjectItemCaseSensitive(array, "name"); + TEST_ASSERT_NULL(found); + + cJSON_Delete(array); +} + static void typecheck_functions_should_check_type(void) { cJSON invalid[1]; @@ -535,6 +557,8 @@ int CJSON_CDECL main(void) RUN_TEST(cjson_array_foreach_should_not_dereference_null_pointer); RUN_TEST(cjson_get_object_item_should_get_object_items); RUN_TEST(cjson_get_object_item_case_sensitive_should_get_object_items); + RUN_TEST(cjson_get_object_item_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(cjson_should_not_parse_to_deeply_nested_jsons); RUN_TEST(cjson_set_number_value_should_set_numbers); From 5cd1dabb3052b9a17c32180faf93804dc56af05a Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 16 Dec 2018 11:16:31 +0100 Subject: [PATCH 145/307] Add yuta-oxo to the Contributors --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 10940b89..6fb2c5c5 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -42,6 +42,7 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB) * [Stephan Gatzka](https://github.com/gatzka) * [Weston Schmidt](https://github.com/schmidtw) * [yangfl](https://github.com/yangfl) +* [yuta-oxo](https://github.com/yuta-oxo) * [Zach Hindes](https://github.com/zhindes) * [Zhao Zhixu](https://github.com/zhaozhixu) From f110bd2e585394bf47baca34a06df2569a9232b6 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 16 Dec 2018 11:17:20 +0100 Subject: [PATCH 146/307] Release Version 1.7.9 --- CHANGELOG.md | 7 +++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55965363..f481641a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +1.7.9 +===== +Fixes: +------ +* Fix a bug where `cJSON_GetObjectItemCaseSensitive` would pass a nullpointer to `strcmp` when called on an array (#315). Thanks @yuweol for reporting. +* Fix error in `cJSON_Utils` where the case sensitivity was not respected (#317). Thanks @yuta-oxo for fixing. + 1.7.8 ===== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index f2ae7eda..b5c6b5b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 8) +set(PROJECT_VERSION_PATCH 9) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 2921ed74..33ecb2e6 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.8 +LIBVERSION = 1.7.9 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index c9c5b61f..e8a62b31 100644 --- a/cJSON.c +++ b/cJSON.c @@ -81,7 +81,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 8) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 9) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 8d453902..ec572ecb 100644 --- a/cJSON.h +++ b/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 8 +#define CJSON_VERSION_PATCH 9 #include From d44b594ab39d0de210ef86cfc72677995a52ab84 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 16 Dec 2018 11:21:35 +0100 Subject: [PATCH 147/307] Add missing changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f481641a..a7c5f3d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Fixes: ------ * Fix a bug where `cJSON_GetObjectItemCaseSensitive` would pass a nullpointer to `strcmp` when called on an array (#315). Thanks @yuweol for reporting. * Fix error in `cJSON_Utils` where the case sensitivity was not respected (#317). Thanks @yuta-oxo for fixing. +* Fix some warnings detected by the Visual Studio Static Analyzer (#307). Thanks @bnason-nf 1.7.8 ===== From 6820448db52885a6828d805c1ce8ee7fcf6e4d65 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 20 Dec 2018 18:04:52 +0100 Subject: [PATCH 148/307] libcjson.pc.in: Use Libs.private instead of Private Thanks @shiluotang --- library_config/libcjson.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library_config/libcjson.pc.in b/library_config/libcjson.pc.in index 7e616bbd..157a4653 100644 --- a/library_config/libcjson.pc.in +++ b/library_config/libcjson.pc.in @@ -6,5 +6,5 @@ Version: @PROJECT_VERSION@ Description: Ultralightweight JSON parser in ANSI C URL: https://github.com/DaveGamble/cJSON Libs: -L${libdir} -lcjson -Libs.Private: -lm +Libs.private: -lm Cflags: -I${includedir} From 563d861f921492dae64e810c6673c991f1d2d3e2 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 20 Dec 2018 18:12:23 +0100 Subject: [PATCH 149/307] cJSON_Utils: sort_lists: Properly split the lists Since `prev` is not used anymore after that by the algorithm it should have been fine anyways, still splitting it correctly in the first place is probably a good idea. Thanks @andysCaplin for the fix! --- cJSON_Utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index f0f9094d..9d07fac0 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -499,6 +499,7 @@ static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive) { /* Split the lists */ second->prev->next = NULL; + second->prev = NULL; } /* Recursively sort the sub-lists. */ From c69134d01746dcf551dd7724b4edb12f922eb0d1 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 20 Dec 2018 18:15:05 +0100 Subject: [PATCH 150/307] Release Version 1.7.10 --- CHANGELOG.md | 7 +++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7c5f3d6..8debcdf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +1.7.10 +====== +Fixes: +------ +* Fix package config file for `libcjson`. Thanks @shiluotang for reporting (#321) +* Correctly split lists in `cJSON_Utils`'s merge sort. Thanks @andysCaplin for the fix (#322) + 1.7.9 ===== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index b5c6b5b2..033a8828 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 9) +set(PROJECT_VERSION_PATCH 10) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 33ecb2e6..8d64fd23 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.9 +LIBVERSION = 1.7.10 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index e8a62b31..74df6ec7 100644 --- a/cJSON.c +++ b/cJSON.c @@ -81,7 +81,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 9) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 10) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index ec572ecb..3279f6ba 100644 --- a/cJSON.h +++ b/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 9 +#define CJSON_VERSION_PATCH 10 #include From add86a6be85ee9a3c82875275cd18d31d927fa7a Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Mon, 18 Mar 2019 22:56:34 +0800 Subject: [PATCH 151/307] Update cJSON.c --- cJSON.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index 74df6ec7..4d2fe26d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -504,7 +504,7 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out } } - /* sprintf failed or buffer overrun occured */ + /* sprintf failed or buffer overrun occurred */ if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) { return false; @@ -1555,7 +1555,7 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu buffer_skip_whitespace(input_buffer); if (!parse_string(current_item, input_buffer)) { - goto fail; /* faile to parse name */ + goto fail; /* failed to parse name */ } buffer_skip_whitespace(input_buffer); From 5a52eaddfd3a36f5e68e73549eb87344812e826b Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sat, 13 Apr 2019 01:44:23 +0200 Subject: [PATCH 152/307] Undef true and false first, fixes #339 Thanks @raiden00pl for reporting --- cJSON.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cJSON.c b/cJSON.c index 74df6ec7..bf38f4c1 100644 --- a/cJSON.c +++ b/cJSON.c @@ -58,7 +58,14 @@ #include "cJSON.h" /* define our own boolean type */ +#ifdef true +#undef true +#endif #define true ((cJSON_bool)1) + +#ifdef false +#undef false +#endif #define false ((cJSON_bool)0) typedef struct { From 9a970b9ff66fae45f45ea4bf9bce602aa9b8d0c7 Mon Sep 17 00:00:00 2001 From: myd7349 Date: Sun, 14 Apr 2019 19:41:28 +0800 Subject: [PATCH 153/307] CMake: Improve install target --- CMakeLists.txt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 033a8828..6e2b2e48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,7 +149,13 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson.pc.in" install(FILES cJSON.h DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/cjson") install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig") -install(TARGETS "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" EXPORT "${CJSON_LIB}") +install(TARGETS "${CJSON_LIB}" + EXPORT "${CJSON_LIB}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}" +) if (BUILD_SHARED_AND_STATIC_LIBS) install(TARGETS "${CJSON_LIB}-static" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}") endif() @@ -186,7 +192,13 @@ if(ENABLE_CJSON_UTILS) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson_utils.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" @ONLY) - install(TARGETS "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" EXPORT "${CJSON_UTILS_LIB}") + install(TARGETS "${CJSON_UTILS_LIB}" + EXPORT "${CJSON_UTILS_LIB}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}" + ) if (BUILD_SHARED_AND_STATIC_LIBS) install(TARGETS "${CJSON_UTILS_LIB}-static" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}") endif() From a43fa56a63920343d0ac8f8e73a6b0447867f459 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 14 Apr 2019 23:13:41 +0200 Subject: [PATCH 154/307] Rewrite cJSON_Minify, fixing buffer overflows, fixes #338 Also first tests for cJSON_Minify. Thanks @bigric3 for reporting --- cJSON.c | 128 ++++++++++++++++++++------------- tests/CMakeLists.txt | 1 + tests/minify_tests.c | 167 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 246 insertions(+), 50 deletions(-) create mode 100644 tests/minify_tests.c diff --git a/cJSON.c b/cJSON.c index bf38f4c1..bf65b56f 100644 --- a/cJSON.c +++ b/cJSON.c @@ -151,6 +151,9 @@ static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) #define internal_realloc realloc #endif +/* strlen of character literals resolved at compile time */ +#define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) + static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) @@ -2637,69 +2640,94 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) return NULL; } -CJSON_PUBLIC(void) cJSON_Minify(char *json) +static void skip_oneline_comment(char **input) { - unsigned char *into = (unsigned char*)json; + *input += static_strlen("//"); - if (json == NULL) + for (; (*input)[0] != '\0'; ++(*input)) { - return; + if ((*input)[0] == '\n') { + *input += static_strlen("\n"); + return; + } } +} + +static void skip_multiline_comment(char **input) +{ + *input += static_strlen("/*"); - while (*json) + for (; (*input)[0] != '\0'; ++(*input)) { - if (*json == ' ') + if (((*input)[0] == '*') && ((*input)[1] == '/')) { - json++; + *input += static_strlen("*/"); + return; } - else if (*json == '\t') - { - /* Whitespace characters. */ - json++; - } - else if (*json == '\r') - { - json++; - } - else if (*json=='\n') - { - json++; - } - else if ((*json == '/') && (json[1] == '/')) - { - /* double-slash comments, to end of line. */ - while (*json && (*json != '\n')) - { - json++; - } + } +} + +static void minify_string(char **input, char **output) { + (*output)[0] = (*input)[0]; + *input += static_strlen("\""); + *output += static_strlen("\""); + + + for (; (*input)[0] != '\0'; ++(*input), ++(*output)) { + (*output)[0] = (*input)[0]; + + if ((*input)[0] == '\"') { + (*output)[0] = '\"'; + *input += static_strlen("\""); + *output += static_strlen("\""); + return; + } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { + (*output)[1] = (*input)[1]; + *input += static_strlen("\""); + *output += static_strlen("\""); } - else if ((*json == '/') && (json[1] == '*')) + } +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + char *into = json; + + if (json == NULL) + { + return; + } + + while (json[0] != '\0') + { + switch (json[0]) { - /* multiline comments. */ - while (*json && !((*json == '*') && (json[1] == '/'))) - { + case ' ': + case '\t': + case '\r': + case '\n': json++; - } - json += 2; - } - else if (*json == '\"') - { - /* string literals, which are \" sensitive. */ - *into++ = (unsigned char)*json++; - while (*json && (*json != '\"')) - { - if (*json == '\\') + break; + + case '/': + if (json[1] == '/') { - *into++ = (unsigned char)*json++; + skip_oneline_comment(&json); } - *into++ = (unsigned char)*json++; - } - *into++ = (unsigned char)*json++; - } - else - { - /* All other characters. */ - *into++ = (unsigned char)*json++; + else if (json[1] == '*') + { + skip_multiline_comment(&json); + } + break; + + case '\"': + minify_string(&json, (char**)&into); + break; + + default: + into[0] = json[0]; + json++; + into++; } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6f1688db..fecc9a9c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -57,6 +57,7 @@ if(ENABLE_CJSON_TEST) compare_tests cjson_add readme_examples + minify_tests ) option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.") diff --git a/tests/minify_tests.c b/tests/minify_tests.c new file mode 100644 index 00000000..e39a9446 --- /dev/null +++ b/tests/minify_tests.c @@ -0,0 +1,167 @@ +/* + Copyright (c) 2009-2019 Dave Gamble and cJSON contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include +#include +#include + +#include "unity/examples/unity_config.h" +#include "unity/src/unity.h" +#include "common.h" + + +static void cjson_minify_should_not_overflow_buffer(void) +{ + char unclosed_multiline_comment[] = "/* bla"; + char pending_escape[] = "\"\\"; + + cJSON_Minify(unclosed_multiline_comment); + TEST_ASSERT_EQUAL_STRING("", unclosed_multiline_comment); + + cJSON_Minify(pending_escape); + TEST_ASSERT_EQUAL_STRING("\"\\", pending_escape); +} + +static void cjson_minify_should_remove_single_line_comments(void) +{ + const char to_minify[] = "{// this is {} \"some kind\" of [] comment /*, don't you see\n}"; + + char* minified = (char*) malloc(sizeof(to_minify)); + TEST_ASSERT_NOT_NULL(minified); + strcpy(minified, to_minify); + + cJSON_Minify(minified); + TEST_ASSERT_EQUAL_STRING("{}", minified); + + free(minified); +} + +static void cjson_minify_should_remove_spaces(void) +{ + const char to_minify[] = "{ \"key\":\ttrue\r\n }"; + + char* minified = (char*) malloc(sizeof(to_minify)); + TEST_ASSERT_NOT_NULL(minified); + strcpy(minified, to_minify); + + cJSON_Minify(minified); + TEST_ASSERT_EQUAL_STRING("{\"key\":true}", minified); + + free(minified); +} + +static void cjson_minify_should_remove_multiline_comments(void) +{ + const char to_minify[] = "{/* this is\n a /* multi\n //line \n {comment \"\\\" */}"; + + char* minified = (char*) malloc(sizeof(to_minify)); + TEST_ASSERT_NOT_NULL(minified); + strcpy(minified, to_minify); + + cJSON_Minify(minified); + TEST_ASSERT_EQUAL_STRING("{}", minified); + + free(minified); +} + +static void cjson_minify_should_not_modify_strings(void) +{ + const char to_minify[] = "\"this is a string \\\" \\t bla\""; + + char* minified = (char*) malloc(sizeof(to_minify)); + TEST_ASSERT_NOT_NULL(minified); + strcpy(minified, to_minify); + + cJSON_Minify(minified); + TEST_ASSERT_EQUAL_STRING(to_minify, minified); + + free(minified); +} + +static void cjson_minify_should_minify_json(void) { + const char to_minify[] = + "{\n" + " \"glossary\": { // comment\n" + " \"title\": \"example glossary\",\n" + " /* multi\n" + " line */\n" + " \"GlossDiv\": {\n" + " \"title\": \"S\",\n" + " \"GlossList\": {\n" + " \"GlossEntry\": {\n" + " \"ID\": \"SGML\",\n" + " \"SortAs\": \"SGML\",\n" + " \"Acronym\": \"SGML\",\n" + " \"Abbrev\": \"ISO 8879:1986\",\n" + " \"GlossDef\": {\n" + " \"GlossSeeAlso\": [\"GML\", \"XML\"]\n" + " },\n" + " \"GlossSee\": \"markup\"\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}"; + const char* minified = + "{" + "\"glossary\":{" + "\"title\":\"example glossary\"," + "\"GlossDiv\":{" + "\"title\":\"S\"," + "\"GlossList\":{" + "\"GlossEntry\":{" + "\"ID\":\"SGML\"," + "\"SortAs\":\"SGML\"," + "\"Acronym\":\"SGML\"," + "\"Abbrev\":\"ISO 8879:1986\"," + "\"GlossDef\":{" + "\"GlossSeeAlso\":[\"GML\",\"XML\"]" + "}," + "\"GlossSee\":\"markup\"" + "}" + "}" + "}" + "}" + "}"; + + char *buffer = (char*) malloc(sizeof(to_minify)); + strcpy(buffer, to_minify); + + cJSON_Minify(buffer); + TEST_ASSERT_EQUAL_STRING(minified, buffer); + + free(buffer); +} + +int CJSON_CDECL main(void) +{ + UNITY_BEGIN(); + + RUN_TEST(cjson_minify_should_not_overflow_buffer); + RUN_TEST(cjson_minify_should_minify_json); + RUN_TEST(cjson_minify_should_remove_single_line_comments); + RUN_TEST(cjson_minify_should_remove_multiline_comments); + RUN_TEST(cjson_minify_should_remove_spaces); + RUN_TEST(cjson_minify_should_not_modify_strings); + + return UNITY_END(); +} From 09ebae8149fb377f40d09615d48d80fe9fe2ed06 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Sun, 14 Apr 2019 23:58:02 +0200 Subject: [PATCH 155/307] Release cJSON 1.7.11 --- CHANGELOG.md | 7 +++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8debcdf3..cf091f05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +1.7.11 +====== +Fixes: +------ +* Fix a bug where cJSON_Minify could overflow it's buffer, both reading and writing. This is a security issue. (see #338). Big thanks @bigric3 for reporting. +* Unset `true` and `false` macros before setting them if they exist. See #339, thanks @raiden00pl for reporting + 1.7.10 ====== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 033a8828..96b375dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 10) +set(PROJECT_VERSION_PATCH 11) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 8d64fd23..93fffccc 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.10 +LIBVERSION = 1.7.11 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index bf65b56f..571f856c 100644 --- a/cJSON.c +++ b/cJSON.c @@ -88,7 +88,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 10) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 11) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 3279f6ba..daf31289 100644 --- a/cJSON.h +++ b/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 10 +#define CJSON_VERSION_PATCH 11 #include From 6b249213dd1bfdb0f2791eec20c65aa4bb4ce301 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Mon, 15 Apr 2019 00:06:35 +0200 Subject: [PATCH 156/307] Fix clang -Wcomma warning --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 571f856c..b0bc3e87 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2673,7 +2673,7 @@ static void minify_string(char **input, char **output) { *output += static_strlen("\""); - for (; (*input)[0] != '\0'; ++(*input), ++(*output)) { + for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { (*output)[0] = (*input)[0]; if ((*input)[0] == '\"') { From 359567fdde253f311545a6c80b0fa6fb62e8ff09 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sun, 28 Apr 2019 10:33:44 +0200 Subject: [PATCH 157/307] Undef true and false first also for cJSON_Utils.c --- cJSON_Utils.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 9d07fac0..7df4db2a 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -50,7 +50,14 @@ #include "cJSON_Utils.h" /* define our own boolean type */ +#ifdef true +#undef true +#endif #define true ((cJSON_bool)1) + +#ifdef false +#undef false +#endif #define false ((cJSON_bool)0) static unsigned char* cJSONUtils_strdup(const unsigned char* const string) From 3a4cfa84c3ce5f7a6439a689dcacbdd42732ed0e Mon Sep 17 00:00:00 2001 From: Simon Sobisch Date: Mon, 6 May 2019 21:07:06 +0200 Subject: [PATCH 158/307] allow to override PIC_FLAGS and compiler std --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 93fffccc..7368179d 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,8 @@ INSTALL_LIBRARY_PATH = $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH) INSTALL ?= cp -a +CC = gcc -std=c89 + # validate gcc version for use fstack-protector-strong MIN_GCC_VERSION = "4.9" GCC_VERSION := "`$(CC) -dumpversion`" @@ -34,7 +36,8 @@ else CFLAGS += -fstack-protector endif -R_CFLAGS = -fPIC -std=c89 -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 -Wcast-qual -Wc++-compat -Wundef -Wswitch-default -Wconversion $(CFLAGS) +PIC_FLAGS = -fPIC +R_CFLAGS = $(PIC_FLAGS) -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 -Wcast-qual -Wc++-compat -Wundef -Wswitch-default -Wconversion $(CFLAGS) uname := $(shell sh -c 'uname -s 2>/dev/null || echo false') From 19ff92da79ee37c81a4cdf1f50a8dd1cbb02e84f Mon Sep 17 00:00:00 2001 From: Winterreise Date: Sat, 11 May 2019 07:37:33 +0800 Subject: [PATCH 159/307] Add link dependency to fix tests link error when ENABLE_CJSON_UTILS is ON --- tests/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fecc9a9c..c7592213 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -102,6 +102,9 @@ if(ENABLE_CJSON_TEST) foreach (cjson_utils_test ${cjson_utils_tests}) add_executable("${cjson_utils_test}" "${cjson_utils_test}.c") target_link_libraries("${cjson_utils_test}" "${CJSON_LIB}" "${CJSON_UTILS_LIB}" unity) + if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") + target_sources(${cjson_utils_test} PRIVATE unity_setup.c) + endif() if(MEMORYCHECK_COMMAND) add_test(NAME "${cjson_utils_test}" COMMAND "${MEMORYCHECK_COMMAND}" ${MEMORYCHECK_COMMAND_OPTIONS} "${CMAKE_CURRENT_BINARY_DIR}/${cjson_utils_test}") From 08d2bc766a82cd75764d036f9efef444590d1cf9 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 16 May 2019 20:01:02 +0200 Subject: [PATCH 160/307] Fix infinite loop in cJSON_Minify --- cJSON.c | 2 ++ tests/minify_tests.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/cJSON.c b/cJSON.c index 3a5dc547..f9c2ffa5 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2717,6 +2717,8 @@ CJSON_PUBLIC(void) cJSON_Minify(char *json) else if (json[1] == '*') { skip_multiline_comment(&json); + } else { + json++; } break; diff --git a/tests/minify_tests.c b/tests/minify_tests.c index e39a9446..000821db 100644 --- a/tests/minify_tests.c +++ b/tests/minify_tests.c @@ -152,6 +152,12 @@ static void cjson_minify_should_minify_json(void) { free(buffer); } +static void cjson_minify_should_not_loop_infinitely(void) { + char string[] = { '8', ' ', '/', ' ', '5', '\n', '\0' }; + /* this should not be an infinite loop */ + cJSON_Minify(string); +} + int CJSON_CDECL main(void) { UNITY_BEGIN(); @@ -162,6 +168,7 @@ int CJSON_CDECL main(void) RUN_TEST(cjson_minify_should_remove_multiline_comments); RUN_TEST(cjson_minify_should_remove_spaces); RUN_TEST(cjson_minify_should_not_modify_strings); + RUN_TEST(cjson_minify_should_not_loop_infinitely); return UNITY_END(); } From 687b1a2fe1e36a965083927981703f8f8d22a78e Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Thu, 16 May 2019 20:03:12 +0200 Subject: [PATCH 161/307] Update version to 1.7.12 --- CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96b375dd..407d359f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 11) +set(PROJECT_VERSION_PATCH 12) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 93fffccc..cf1f09a9 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.11 +LIBVERSION = 1.7.12 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index f9c2ffa5..60b72c01 100644 --- a/cJSON.c +++ b/cJSON.c @@ -88,7 +88,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 11) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 12) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index daf31289..592986b8 100644 --- a/cJSON.h +++ b/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 11 +#define CJSON_VERSION_PATCH 12 #include From b93fd34044a3ab3d956b1a6c733d609853ada854 Mon Sep 17 00:00:00 2001 From: Max Bruckner Date: Fri, 17 May 2019 00:37:26 +0200 Subject: [PATCH 162/307] Update changelog and contributors --- CHANGELOG.md | 9 +++++++++ CONTRIBUTORS.md | 3 +++ 2 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf091f05..4afe782d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +1.7.12 +====== +Fixes: +------ +* Fix infinite loop in `cJSON_Minify` (potential Denial of Service), thanks @Alanscut for reporting. See #354 +* Fix link error for Visual Studio. Thanks @tan-wei, see #352 +* Undefine `true` and `false` for `cJSON_Utils` before redefining them. Thanks @raiden00pl, see #347 + + 1.7.11 ====== Fixes: diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 6fb2c5c5..c6a73108 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -14,6 +14,7 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB) * [Debora Grosse](https://github.com/DeboraG) * [dieyushi](https://github.com/dieyushi) * [Dōngwén Huáng (黄东文)](https://github.com/DongwenHuang) +* [Donough Liu](https://github.com/ldm0) * Eswar Yaganti * [Evan Todd](https://github.com/etodd) * [Fabrice Fontaine](https://github.com/ffontaine) @@ -34,12 +35,14 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB) * [Pawel Winogrodzki](https://github.com/PawelWMS) * [prefetchnta](https://github.com/prefetchnta) * [Rafael Leal Dias](https://github.com/rafaeldias) +* [raiden00pl](https://github.com/raiden00pl) * [Robin Mallinson](https://github.com/rmallins) * [Rod Vagg](https://github.com/rvagg) * [Roland Meertens](https://github.com/rmeertens) * [Romain Porte](https://github.com/MicroJoe) * [Simon Ricaldone](https://github.com/simon-p-r) * [Stephan Gatzka](https://github.com/gatzka) +* [tan-wei](https://github.com/tan-wei) * [Weston Schmidt](https://github.com/schmidtw) * [yangfl](https://github.com/yangfl) * [yuta-oxo](https://github.com/yuta-oxo) From 5fe80a94b64f542f100634c4caea843b254ed3e1 Mon Sep 17 00:00:00 2001 From: Alan_scut Date: Wed, 22 May 2019 10:24:13 +0800 Subject: [PATCH 163/307] add comment for cJSON_Minify function --- cJSON.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cJSON.h b/cJSON.h index 592986b8..71a6d2ed 100644 --- a/cJSON.h +++ b/cJSON.h @@ -250,7 +250,9 @@ The item->next and ->prev pointers are always zero on return from Duplicate. */ * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); - +/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings */ +/* The input pointer json cannot point to a read-only address area, such as a string constant, + * but should point to a readable and writable adress area. */ CJSON_PUBLIC(void) cJSON_Minify(char *json); /* Helper functions for creating and adding items to an object at the same time. From 16f56300e48716dfb2e5af978f38992c55257c6d Mon Sep 17 00:00:00 2001 From: singku Date: Wed, 29 May 2019 21:25:33 +0000 Subject: [PATCH 164/307] Replace strcpy with strncpy, sprintf with snprintf --- cJSON.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/cJSON.c b/cJSON.c index 60b72c01..5f30d6ac 100644 --- a/cJSON.c +++ b/cJSON.c @@ -95,7 +95,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { CJSON_PUBLIC(const char*) cJSON_Version(void) { static char version[15]; - sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + snprintf(version, sizeof(version), "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); return version; } @@ -499,22 +499,22 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out /* This checks for NaN and Infinity */ if ((d * 0) != 0) { - length = sprintf((char*)number_buffer, "null"); + length = snprintf((char*)number_buffer, sizeof(number_buffer), "null"); } else { /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ - length = sprintf((char*)number_buffer, "%1.15g", d); + length = snprintf((char*)number_buffer, sizeof(number_buffer), "%1.15g", d); /* Check whether the original double can be recovered */ if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) { /* If not, print with 17 decimal places of precision */ - length = sprintf((char*)number_buffer, "%1.17g", d); + length = snprintf((char*)number_buffer, sizeof(number_buffer), "%1.17g", d); } } - /* sprintf failed or buffer overrun occurred */ + /* snprintf failed or buffer overrun occurred */ if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) { return false; @@ -848,15 +848,16 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe return false; } + const char quotes[] = "\"\""; /* empty string */ if (input == NULL) { - output = ensure(output_buffer, sizeof("\"\"")); + output = ensure(output_buffer, sizeof(quotes)); if (output == NULL) { return false; } - strcpy((char*)output, "\"\""); + strncpy((char*)output, quotes, output_buffer->length - output_buffer->offset); return true; } @@ -887,7 +888,7 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe } output_length = (size_t)(input_pointer - input) + escape_characters; - output = ensure(output_buffer, output_length + sizeof("\"\"")); + output = ensure(output_buffer, output_length + sizeof(quotes)); if (output == NULL) { return false; @@ -943,7 +944,7 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe break; default: /* escape and print as unicode codepoint */ - sprintf((char*)output_pointer, "u%04x", *input_pointer); + snprintf((char*)output_pointer, output_buffer->length - (output_pointer - output_buffer->buffer), "u%04x", *input_pointer); output_pointer += 4; break; } @@ -1286,32 +1287,38 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp switch ((item->type) & 0xFF) { case cJSON_NULL: - output = ensure(output_buffer, 5); + { + const char buff[] = "null"; + output = ensure(output_buffer, sizeof(buff)); if (output == NULL) { return false; } - strcpy((char*)output, "null"); + strncpy((char*)output, buff, output_buffer->length - output_buffer->offset); return true; - + } case cJSON_False: - output = ensure(output_buffer, 6); + { + const char buff[] = "false"; + output = ensure(output_buffer, sizeof(buff)); if (output == NULL) { return false; } - strcpy((char*)output, "false"); + strncpy((char*)output, buff, output_buffer->length - output_buffer->offset); return true; - + } case cJSON_True: - output = ensure(output_buffer, 5); + { + const char buff[] = "true"; + output = ensure(output_buffer, sizeof(buff)); if (output == NULL) { return false; } - strcpy((char*)output, "true"); + strncpy((char*)output, buff, output_buffer->length - output_buffer->offset); return true; - + } case cJSON_Number: return print_number(item, output_buffer); From c9e8a68b00a39d14c91aade54910584d01470a59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Malowany?= Date: Mon, 10 Jun 2019 10:59:31 +0200 Subject: [PATCH 165/307] Fix clang -Wfloat-equal warning --- CMakeLists.txt | 1 + Makefile | 2 +- cJSON.c | 12 +++++++++--- cJSON.h | 5 +++++ cJSON_Utils.c | 12 ++++++++++-- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 407d359f..dccf998e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) -Wmissing-variable-declarations -Wused-but-marked-unused -Wswitch-enum + -Wfloat-equal ) elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") # Disable warning c4001 - nonstandard extension 'single line comment' was used diff --git a/Makefile b/Makefile index cf1f09a9..e70f5426 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ else CFLAGS += -fstack-protector endif -R_CFLAGS = -fPIC -std=c89 -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 -Wcast-qual -Wc++-compat -Wundef -Wswitch-default -Wconversion $(CFLAGS) +R_CFLAGS = -fPIC -std=c89 -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 -Wcast-qual -Wc++-compat -Wundef -Wswitch-default -Wconversion -Wfloat-equal $(CFLAGS) uname := $(shell sh -c 'uname -s 2>/dev/null || echo false') diff --git a/cJSON.c b/cJSON.c index 60b72c01..f643073f 100644 --- a/cJSON.c +++ b/cJSON.c @@ -480,6 +480,12 @@ static void update_offset(printbuffer * const buffer) buffer->offset += strlen((const char*)buffer_pointer); } +/* securely comparison of floating-point variables */ +static cJSON_bool compare_double(double a, double b) +{ + return (fabs(a - b) <= a * CJSON_DOUBLE_PRECIION); +} + /* Render the number nicely from the given item into a string. */ static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) { @@ -497,7 +503,7 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out } /* This checks for NaN and Infinity */ - if ((d * 0) != 0) + if (!compare_double(d * 0, 0)) { length = sprintf((char*)number_buffer, "null"); } @@ -507,7 +513,7 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out length = sprintf((char*)number_buffer, "%1.15g", d); /* Check whether the original double can be recovered */ - if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) { /* If not, print with 17 decimal places of precision */ length = sprintf((char*)number_buffer, "%1.17g", d); @@ -2876,7 +2882,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons return true; case cJSON_Number: - if (a->valuedouble == b->valuedouble) + if (compare_double(a->valuedouble, b->valuedouble)) { return true; } diff --git a/cJSON.h b/cJSON.h index 592986b8..ef701a2d 100644 --- a/cJSON.h +++ b/cJSON.h @@ -137,6 +137,11 @@ typedef int cJSON_bool; #define CJSON_NESTING_LIMIT 1000 #endif +/* Precision of double variables comparison */ +#ifndef CJSON_DOUBLE_PRECIION +#define CJSON_DOUBLE_PRECIION .00001 +#endif + /* returns the version of cJSON as a string */ CJSON_PUBLIC(const char*) cJSON_Version(void); diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 7df4db2a..43e2630b 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -39,6 +39,7 @@ #include #include #include +#include #if defined(_MSC_VER) #pragma warning (pop) @@ -105,6 +106,13 @@ static int compare_strings(const unsigned char *string1, const unsigned char *st return tolower(*string1) - tolower(*string2); } +/* securely comparison of floating-point variables */ +static cJSON_bool compare_double(double a, double b) +{ + return (fabs(a - b) <= a * CJSON_DOUBLE_PRECIION); +} + + /* Compare the next path element of two JSON pointers, two NULL pointers are considered unequal: */ static cJSON_bool compare_pointers(const unsigned char *name, const unsigned char *pointer, const cJSON_bool case_sensitive) { @@ -595,7 +603,7 @@ static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensiti { case cJSON_Number: /* numeric mismatch. */ - if ((a->valueint != b->valueint) || (a->valuedouble != b->valuedouble)) + if ((a->valueint != b->valueint) || (!compare_double(a->valuedouble, b->valuedouble))) { return false; } @@ -1135,7 +1143,7 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa switch (from->type & 0xFF) { case cJSON_Number: - if ((from->valueint != to->valueint) || (from->valuedouble != to->valuedouble)) + if ((from->valueint != to->valueint) || (compare_double(from->valuedouble, to->valuedouble))) { compose_patch(patches, (const unsigned char*)"replace", path, NULL, to); } From 110f184d18c3a33debc45bcf066e32fb61021baf Mon Sep 17 00:00:00 2001 From: Sanjeev BA Date: Sun, 16 Jun 2019 07:58:03 +0900 Subject: [PATCH 166/307] Fix typos. Signed-off-by: Sanjeev BA --- cJSON.c | 2 +- cJSON.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cJSON.c b/cJSON.c index 60b72c01..85e8ba64 100644 --- a/cJSON.c +++ b/cJSON.c @@ -132,7 +132,7 @@ typedef struct internal_hooks } internal_hooks; #if defined(_MSC_VER) -/* 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 internal_malloc(size_t size) { return malloc(size); diff --git a/cJSON.h b/cJSON.h index 592986b8..73992599 100644 --- a/cJSON.h +++ b/cJSON.h @@ -203,7 +203,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); /* Create a string where valuestring references a string so * it will not be freed by cJSON_Delete */ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); -/* Create an object/arrray that only references it's elements so +/* Create an object/array that only references it's elements so * they will not be freed by cJSON_Delete */ CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); @@ -225,7 +225,7 @@ CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJ CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); -/* Remove/Detatch items from Arrays/Objects. */ +/* Remove/Detach items from Arrays/Objects. */ CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); From 85ceadb4b42bd8c80893595bf25a4a8acb24dae4 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Tue, 25 Jun 2019 17:25:23 +0800 Subject: [PATCH 167/307] Add a comment to the parameter count of the cJSON_CreateIntArray function. --- cJSON.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cJSON.h b/cJSON.h index 592986b8..a2ae97f4 100644 --- a/cJSON.h +++ b/cJSON.h @@ -208,7 +208,8 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); -/* These utilities create an Array of count items. */ +/* These utilities create an Array of count items. * +*The parameter count cannot be greater than the number of elements in the number array,otherwise array access will be out of bounds.*/ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); From 9d766f07a793e3277ff14c231540887179001651 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Fri, 28 Jun 2019 14:22:02 +0800 Subject: [PATCH 168/307] fix const cast warnings in cJSON_GetStringValue --- cJSON.c | 2 +- cJSON.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index 60b72c01..87f815be 100644 --- a/cJSON.c +++ b/cJSON.c @@ -79,7 +79,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) return (const char*) (global_error.json + global_error.position); } -CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) { if (!cJSON_IsString(item)) { return NULL; } diff --git a/cJSON.h b/cJSON.h index 592986b8..09bc74c3 100644 --- a/cJSON.h +++ b/cJSON.h @@ -174,7 +174,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *st CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); /* Check if the item is a string and return its valuestring */ -CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); /* These functions check the type of an item */ CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); From f7f175fdf298b644efdd43e38be66608c13ccdb6 Mon Sep 17 00:00:00 2001 From: Randy Date: Thu, 11 Jul 2019 13:56:07 +0200 Subject: [PATCH 169/307] add fuzz target --- fuzzing/cjson_read_fuzzer.cc | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 fuzzing/cjson_read_fuzzer.cc diff --git a/fuzzing/cjson_read_fuzzer.cc b/fuzzing/cjson_read_fuzzer.cc new file mode 100644 index 00000000..d7af5c2f --- /dev/null +++ b/fuzzing/cjson_read_fuzzer.cc @@ -0,0 +1,41 @@ +#include +#include + +#include "../cJSON.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + if((data[0] == '\0') || (size < 3) || (data[1] == '\0')) return 0; + + cJSON *json = cJSON_Parse((const char*)data + 2); + + if(json == NULL) return 0; + + int do_format = 0; + char *printed_json = NULL; + + if(data[1] == 'f') do_format = 1; + + if(data[0] == 'b') + { + /* buffered printing */ + printed_json = cJSON_PrintBuffered(json, 1, do_format); + } + else + { + /* unbuffered printing */ + if(do_format) + { + printed_json = cJSON_Print(json); + } + else + { + printed_json = cJSON_PrintUnformatted(json); + } + } + + if(printed_json != NULL) free(printed_json); + cJSON_Delete(json); + + return 0; +} From 2691e142f4a881b470e7d5e889ef4ca4a589cadf Mon Sep 17 00:00:00 2001 From: Randy Date: Thu, 11 Jul 2019 14:42:27 +0200 Subject: [PATCH 170/307] update fuzzer --- fuzzing/cjson_read_fuzzer.cc | 38 +++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/fuzzing/cjson_read_fuzzer.cc b/fuzzing/cjson_read_fuzzer.cc index d7af5c2f..be2fe673 100644 --- a/fuzzing/cjson_read_fuzzer.cc +++ b/fuzzing/cjson_read_fuzzer.cc @@ -1,30 +1,38 @@ #include #include +#include #include "../cJSON.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - if((data[0] == '\0') || (size < 3) || (data[1] == '\0')) return 0; + size_t offset = 4; - cJSON *json = cJSON_Parse((const char*)data + 2); + if(size < offset) return 0; + if(data[0] != '1' && data[0] != '0') return 0; + if(data[1] != '1' && data[1] != '0') return 0; + if(data[2] != '1' && data[2] != '0') return 0; + if(data[3] != '1' && data[3] != '0') return 0; + + int minify = data[0] == '1' ? 1 : 0; + int require_termination = data[1] == '1' ? 1 : 0; + int formatted = data[2] == '1' ? 1 : 0; + int buffered = data[3] == '1' ? 1 : 0; + + cJSON *json = cJSON_ParseWithOpts((const char*)data + offset, NULL, require_termination); if(json == NULL) return 0; - int do_format = 0; char *printed_json = NULL; - if(data[1] == 'f') do_format = 1; - - if(data[0] == 'b') + if(buffered) { - /* buffered printing */ - printed_json = cJSON_PrintBuffered(json, 1, do_format); + printed_json = cJSON_PrintBuffered(json, 1, formatted); } else { /* unbuffered printing */ - if(do_format) + if(formatted) { printed_json = cJSON_Print(json); } @@ -35,6 +43,18 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) } if(printed_json != NULL) free(printed_json); + + if(minify) + { + unsigned char *copied = (unsigned char*)malloc(size); + + memcpy(copied, data + offset, size); + + cJSON_Minify((char*)printed_json); + free(copied); + } + + cJSON_Delete(json); return 0; From e6bc5d16e6e1c336523fbda6493c4f7ee3863415 Mon Sep 17 00:00:00 2001 From: Randy Date: Thu, 11 Jul 2019 15:03:04 +0200 Subject: [PATCH 171/307] update fuzzer --- fuzzing/cjson_read_fuzzer.cc | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/fuzzing/cjson_read_fuzzer.cc b/fuzzing/cjson_read_fuzzer.cc index be2fe673..57cbd0cd 100644 --- a/fuzzing/cjson_read_fuzzer.cc +++ b/fuzzing/cjson_read_fuzzer.cc @@ -19,9 +19,19 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) int formatted = data[2] == '1' ? 1 : 0; int buffered = data[3] == '1' ? 1 : 0; - cJSON *json = cJSON_ParseWithOpts((const char*)data + offset, NULL, require_termination); + unsigned char *copied = (unsigned char*)malloc(size); + if(copied == NULL) return 0; - if(json == NULL) return 0; + memcpy(copied, data, size); + copied[size-1] = '\0'; + + cJSON *json = cJSON_ParseWithOpts((const char*)copied + offset, NULL, require_termination); + + if(json == NULL) + { + free(copied); + return 0; + } char *printed_json = NULL; @@ -46,16 +56,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) if(minify) { - unsigned char *copied = (unsigned char*)malloc(size); - - memcpy(copied, data + offset, size); - - cJSON_Minify((char*)printed_json); - free(copied); + cJSON_Minify((char*)copied + offset); } - cJSON_Delete(json); + free(copied); return 0; } From 2d6db59c7bddee0f052b5ed511bcfd4306badaa9 Mon Sep 17 00:00:00 2001 From: Randy Date: Thu, 11 Jul 2019 15:09:10 +0200 Subject: [PATCH 172/307] update fuzzer --- fuzzing/cjson_read_fuzzer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzing/cjson_read_fuzzer.cc b/fuzzing/cjson_read_fuzzer.cc index 57cbd0cd..3b768941 100644 --- a/fuzzing/cjson_read_fuzzer.cc +++ b/fuzzing/cjson_read_fuzzer.cc @@ -8,7 +8,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { size_t offset = 4; - if(size < offset) return 0; + if(size <= offset) return 0; if(data[0] != '1' && data[0] != '0') return 0; if(data[1] != '1' && data[1] != '0') return 0; if(data[2] != '1' && data[2] != '0') return 0; From c680faea56d4089d857c091f39679384fe6f392e Mon Sep 17 00:00:00 2001 From: Vemake Date: Wed, 24 Jul 2019 20:46:41 +0800 Subject: [PATCH 173/307] Update Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index cf1f09a9..3cfd6f8f 100644 --- a/Makefile +++ b/Makefile @@ -104,7 +104,7 @@ $(UTILS_SHARED_VERSION): $(UTILS_OBJ) #cJSON $(CJSON_OBJ): cJSON.c cJSON.h #cJSON_Utils -$(UTILS_OBJ): cJSON_Utils.c cJSON_Utils.h +$(UTILS_OBJ): cJSON_Utils.c cJSON_Utils.h cJSON.h #links .so -> .so.1 -> .so.1.0.0 From 166c814cda8e78bcf27fbbc815f945ceb21af5c5 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Mon, 12 Aug 2019 17:06:29 +0800 Subject: [PATCH 174/307] eliminate warning when compiling cJSON --- tests/unity/src/unity.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/unity/src/unity.c b/tests/unity/src/unity.c index 0f2d2dea..d02610a7 100644 --- a/tests/unity/src/unity.c +++ b/tests/unity/src/unity.c @@ -268,14 +268,14 @@ void UnityPrintFloat(const UNITY_DOUBLE input_number) UNITY_DOUBLE number = input_number; /* print minus sign (including for negative zero) */ - if (number < 0.0f || (number == 0.0f && 1.0f / number < 0.0f)) + if (number < (double)0.0f || (number == (double)0.0f && (double)1.0f / number < (double)0.0f)) { UNITY_OUTPUT_CHAR('-'); number = -number; } /* handle zero, NaN, and +/- infinity */ - if (number == 0.0f) UnityPrint("0"); + if (number == (double)0.0f) UnityPrint("0"); else if (isnan(number)) UnityPrint("nan"); else if (isinf(number)) UnityPrint("inf"); else @@ -286,10 +286,10 @@ void UnityPrintFloat(const UNITY_DOUBLE input_number) char buf[16]; /* scale up or down by powers of 10 */ - while (number < 100000.0f / 1e6f) { number *= 1e6f; exponent -= 6; } - while (number < 100000.0f) { number *= 10.0f; exponent--; } - while (number > 1000000.0f * 1e6f) { number /= 1e6f; exponent += 6; } - while (number > 1000000.0f) { number /= 10.0f; exponent++; } + while (number < (double)(100000.0f / 1e6f)) { number *= (double)1e6f; exponent -= 6; } + while (number < (double)100000.0f) { number *= (double)10.0f; exponent--; } + while (number > (double)(1000000.0f * 1e6f)) { number /= (double)1e6f; exponent += 6; } + while (number > (double)1000000.0f) { number /= (double)10.0f; exponent++; } /* round to nearest integer */ n = ((UNITY_INT32)(number + number) + 1) / 2; From b6da0d6565f7b5095fd5ecb9aa197393324788e0 Mon Sep 17 00:00:00 2001 From: Sang-Heon Jeon Date: Sat, 24 Aug 2019 22:43:33 +0900 Subject: [PATCH 175/307] Correct typo error --- cJSON.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.h b/cJSON.h index 592986b8..c00ea4e9 100644 --- a/cJSON.h +++ b/cJSON.h @@ -160,7 +160,7 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); /* Delete a cJSON entity and all subentities. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); /* Returns the number of items in an array (or object). */ CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); From bd1a375028a29f2ee39a96ac8459b8ea4711ed0a Mon Sep 17 00:00:00 2001 From: Randy Date: Sat, 24 Aug 2019 17:42:48 +0200 Subject: [PATCH 176/307] add fuzzer driver, integrate with build system --- fuzzing/CMakeLists.txt | 5 ++++ fuzzing/cjson_read_fuzzer.cc | 24 ++++++++++------ fuzzing/fuzz_main.c | 56 ++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 fuzzing/fuzz_main.c diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index fdd7126e..84278e8c 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -26,3 +26,8 @@ if (ENABLE_FUZZING) endif() + +if(ENABLE_CJSON_TEST) + ADD_EXECUTABLE(fuzz_main fuzz_main.c) + TARGET_LINK_LIBRARIES(fuzz_main cjson) +endif() \ No newline at end of file diff --git a/fuzzing/cjson_read_fuzzer.cc b/fuzzing/cjson_read_fuzzer.cc index 3b768941..4ec43220 100644 --- a/fuzzing/cjson_read_fuzzer.cc +++ b/fuzzing/cjson_read_fuzzer.cc @@ -4,9 +4,17 @@ #include "../cJSON.h" -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +#ifdef __cplusplus +extern "C" +#endif +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + cJSON *json; size_t offset = 4; + unsigned char *copied; + char *printed_json = NULL; + int minify, require_termination, formatted, buffered; + if(size <= offset) return 0; if(data[0] != '1' && data[0] != '0') return 0; @@ -14,18 +22,18 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) if(data[2] != '1' && data[2] != '0') return 0; if(data[3] != '1' && data[3] != '0') return 0; - int minify = data[0] == '1' ? 1 : 0; - int require_termination = data[1] == '1' ? 1 : 0; - int formatted = data[2] == '1' ? 1 : 0; - int buffered = data[3] == '1' ? 1 : 0; + minify = data[0] == '1' ? 1 : 0; + require_termination = data[1] == '1' ? 1 : 0; + formatted = data[2] == '1' ? 1 : 0; + buffered = data[3] == '1' ? 1 : 0; - unsigned char *copied = (unsigned char*)malloc(size); + copied = (unsigned char*)malloc(size); if(copied == NULL) return 0; memcpy(copied, data, size); copied[size-1] = '\0'; - cJSON *json = cJSON_ParseWithOpts((const char*)copied + offset, NULL, require_termination); + json = cJSON_ParseWithOpts((const char*)copied + offset, NULL, require_termination); if(json == NULL) { @@ -33,8 +41,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) return 0; } - char *printed_json = NULL; - if(buffered) { printed_json = cJSON_PrintBuffered(json, 1, formatted); diff --git a/fuzzing/fuzz_main.c b/fuzzing/fuzz_main.c new file mode 100644 index 00000000..e004115f --- /dev/null +++ b/fuzzing/fuzz_main.c @@ -0,0 +1,56 @@ +#include +#include +#include + +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); /* required by C90 */ + +#include "cjson_read_fuzzer.cc" + +/* fuzz target entry point, works without libFuzzer */ + +int main(int argc, char **argv) +{ + FILE *f; + char *buf = NULL; + long siz_buf; + + if(argc < 2) + { + fprintf(stderr, "no input file\n"); + goto err; + } + + f = fopen(argv[1], "rb"); + if(f == NULL) + { + fprintf(stderr, "error opening input file %s\n", argv[1]); + goto err; + } + + fseek(f, 0, SEEK_END); + + siz_buf = ftell(f); + rewind(f); + + if(siz_buf < 1) goto err; + + buf = (char*)malloc((size_t)siz_buf); + if(buf == NULL) + { + fprintf(stderr, "malloc() failed\n"); + goto err; + } + + if(fread(buf, (size_t)siz_buf, 1, f) != 1) + { + fprintf(stderr, "fread() failed\n"); + goto err; + } + + (void)LLVMFuzzerTestOneInput((uint8_t*)buf, (size_t)siz_buf); + +err: + free(buf); + + return 0; +} From c61573f1af9df53515cbdc5dae39a9b2e8a7740f Mon Sep 17 00:00:00 2001 From: Alanscut Date: Wed, 11 Sep 2019 09:51:30 +0800 Subject: [PATCH 177/307] format adjustment --- cJSON.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cJSON.h b/cJSON.h index a2ae97f4..1e8567a6 100644 --- a/cJSON.h +++ b/cJSON.h @@ -208,8 +208,8 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); -/* These utilities create an Array of count items. * -*The parameter count cannot be greater than the number of elements in the number array,otherwise array access will be out of bounds.*/ +/* These utilities create an Array of count items. + * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); From 189b51c5dae85e193ec1601079e4a2a61145f3b4 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Wed, 11 Sep 2019 10:42:44 +0800 Subject: [PATCH 178/307] format comment --- cJSON.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cJSON.h b/cJSON.h index f19692b1..42c1cc61 100644 --- a/cJSON.h +++ b/cJSON.h @@ -245,14 +245,14 @@ CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const ch /* Duplicate a cJSON item */ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will -need to be released. With recurse!=0, it will duplicate any children connected to the item. -The item->next and ->prev pointers are always zero on return from Duplicate. */ + * need to be released. With recurse!=0, it will duplicate any children connected to the item. + * The item->next and ->prev pointers are always zero on return from Duplicate. */ /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); -/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings */ -/* The input pointer json cannot point to a read-only address area, such as a string constant, +/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. + * The input pointer json cannot point to a read-only address area, such as a string constant, * but should point to a readable and writable adress area. */ CJSON_PUBLIC(void) cJSON_Minify(char *json); From ae49da2b61a378b9c0e07572ca759cd305c8b9c8 Mon Sep 17 00:00:00 2001 From: Alanscut <948467222@qq.com> Date: Sat, 21 Sep 2019 17:42:25 +0800 Subject: [PATCH 179/307] Revert "Replace strcpy with strncpy, sprintf with snprintf" --- cJSON.c | 43 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/cJSON.c b/cJSON.c index f04010fa..85e8ba64 100644 --- a/cJSON.c +++ b/cJSON.c @@ -95,7 +95,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { CJSON_PUBLIC(const char*) cJSON_Version(void) { static char version[15]; - snprintf(version, sizeof(version), "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); return version; } @@ -499,22 +499,22 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out /* This checks for NaN and Infinity */ if ((d * 0) != 0) { - length = snprintf((char*)number_buffer, sizeof(number_buffer), "null"); + length = sprintf((char*)number_buffer, "null"); } else { /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ - length = snprintf((char*)number_buffer, sizeof(number_buffer), "%1.15g", d); + length = sprintf((char*)number_buffer, "%1.15g", d); /* Check whether the original double can be recovered */ if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) { /* If not, print with 17 decimal places of precision */ - length = snprintf((char*)number_buffer, sizeof(number_buffer), "%1.17g", d); + length = sprintf((char*)number_buffer, "%1.17g", d); } } - /* snprintf failed or buffer overrun occurred */ + /* sprintf failed or buffer overrun occurred */ if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) { return false; @@ -848,16 +848,15 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe return false; } - const char quotes[] = "\"\""; /* empty string */ if (input == NULL) { - output = ensure(output_buffer, sizeof(quotes)); + output = ensure(output_buffer, sizeof("\"\"")); if (output == NULL) { return false; } - strncpy((char*)output, quotes, output_buffer->length - output_buffer->offset); + strcpy((char*)output, "\"\""); return true; } @@ -888,7 +887,7 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe } output_length = (size_t)(input_pointer - input) + escape_characters; - output = ensure(output_buffer, output_length + sizeof(quotes)); + output = ensure(output_buffer, output_length + sizeof("\"\"")); if (output == NULL) { return false; @@ -944,7 +943,7 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe break; default: /* escape and print as unicode codepoint */ - snprintf((char*)output_pointer, output_buffer->length - (output_pointer - output_buffer->buffer), "u%04x", *input_pointer); + sprintf((char*)output_pointer, "u%04x", *input_pointer); output_pointer += 4; break; } @@ -1287,38 +1286,32 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp switch ((item->type) & 0xFF) { case cJSON_NULL: - { - const char buff[] = "null"; - output = ensure(output_buffer, sizeof(buff)); + output = ensure(output_buffer, 5); if (output == NULL) { return false; } - strncpy((char*)output, buff, output_buffer->length - output_buffer->offset); + strcpy((char*)output, "null"); return true; - } + case cJSON_False: - { - const char buff[] = "false"; - output = ensure(output_buffer, sizeof(buff)); + output = ensure(output_buffer, 6); if (output == NULL) { return false; } - strncpy((char*)output, buff, output_buffer->length - output_buffer->offset); + strcpy((char*)output, "false"); return true; - } + case cJSON_True: - { - const char buff[] = "true"; - output = ensure(output_buffer, sizeof(buff)); + output = ensure(output_buffer, 5); if (output == NULL) { return false; } - strncpy((char*)output, buff, output_buffer->length - output_buffer->offset); + strcpy((char*)output, "true"); return true; - } + case cJSON_Number: return print_number(item, output_buffer); From e52b212dbfc583f933ee199bd54e82fdfa8da561 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Sun, 29 Sep 2019 18:53:21 +0800 Subject: [PATCH 180/307] fix typos in REAM.md file --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3b39c854..06b0de9f 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,7 @@ Note that you have to delete them at some point, otherwise you will get a memory You can create an empty array with `cJSON_CreateArray`. `cJSON_CreateArrayReference` can be used to create an array that doesn't "own" its content, so its content doesn't get deleted by `cJSON_Delete`. To add items to an array, use `cJSON_AddItemToArray` to append items to the end. -Using `cJSON_AddItemReferenceToArray` an element can be added as a reference to another item, array or string. This means that `cJSON_Delete` will not delete that items `child` or `valuestring` properties, so no double frees are occuring if they are already used elsewhere. +Using `cJSON_AddItemReferenceToArray` an element can be added as a reference to another item, array or string. This means that `cJSON_Delete` will not delete that items `child` or `valuestring` properties, so no double frees are occurring if they are already used elsewhere. To insert items in the middle, use `cJSON_InsertItemInArray`. It will insert an item at the given 0 based index and shift all the existing items to the right. If you want to take an item out of an array at a given index and continue using it, use `cJSON_DetachItemFromArray`, it will return the detached item, so be sure to assign it to a pointer, otherwise you will have a memory leak. @@ -221,7 +221,7 @@ Because an array is stored as a linked list, iterating it via index is inefficie You can create an empty object with `cJSON_CreateObject`. `cJSON_CreateObjectReference` can be used to create an object that doesn't "own" its content, so its content doesn't get deleted by `cJSON_Delete`. To add items to an object, use `cJSON_AddItemToObject`. Use `cJSON_AddItemToObjectCS` to add an item to an object with a name that is a constant or reference (key of the item, `string` in the `cJSON` struct), so that it doesn't get freed by `cJSON_Delete`. -Using `cJSON_AddItemReferenceToArray` an element can be added as a reference to another object, array or string. This means that `cJSON_Delete` will not delete that items `child` or `valuestring` properties, so no double frees are occuring if they are already used elsewhere. +Using `cJSON_AddItemReferenceToArray` an element can be added as a reference to another object, array or string. This means that `cJSON_Delete` will not delete that items `child` or `valuestring` properties, so no double frees are occurring if they are already used elsewhere. If you want to take an item out of an object, use `cJSON_DetachItemFromObjectCaseSensitive`, it will return the detached item, so be sure to assign it to a pointer, otherwise you will have a memory leak. @@ -326,7 +326,7 @@ char* create_monitor(void) goto end; } /* after creation was successful, immediately add it to the monitor, - * thereby transfering ownership of the pointer to it */ + * thereby transferring ownership of the pointer to it */ cJSON_AddItemToObject(monitor, "name", name); resolutions = cJSON_CreateArray(); From dc56e24f7f1d3ffc72e8b5a0039c6137b43e89d4 Mon Sep 17 00:00:00 2001 From: randy408 Date: Mon, 14 Oct 2019 17:12:13 +0200 Subject: [PATCH 181/307] add build script --- fuzzing/ossfuzz.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 fuzzing/ossfuzz.sh diff --git a/fuzzing/ossfuzz.sh b/fuzzing/ossfuzz.sh new file mode 100644 index 00000000..8de60e4a --- /dev/null +++ b/fuzzing/ossfuzz.sh @@ -0,0 +1,19 @@ +#!/bin/bash -eu + +# This script is meant to be run by +# https://github.com/google/oss-fuzz/blob/master/projects/cjson/Dockerfile + +mkdir build +cd build +cmake -DBUILD_SHARED_LIBS=OFF -DENABLE_CJSON_TEST=OFF .. +make -j$(nproc) + +$CXX $CXXFLAGS -std=c++11 -I. \ + $SRC/cjson/fuzzing/cjson_read_fuzzer.cc \ + -o $OUT/cjson_read_fuzzer \ + $LIB_FUZZING_ENGINE $SRC/cjson/build/libcjson.a + +find $SRC/cjson/fuzzing/inputs -name "*" | \ + xargs zip $OUT/cjson_read_fuzzer_seed_corpus.zip + +cp $SRC/cjson/fuzzing/json.dict $OUT/cjson_read_fuzzer.dict From 26772a8ef7affe5ed96c831eddfb6b69146cc2d2 Mon Sep 17 00:00:00 2001 From: Bernt Johan Damslora Date: Thu, 17 Oct 2019 14:03:15 +0200 Subject: [PATCH 182/307] Add const qualifier to cJSON_CreateStringArray Adds a const qualifier to the strings in the array to avoid discarding it from arguments. --- cJSON.c | 2 +- cJSON.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index 85e8ba64..96b65f13 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2524,7 +2524,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) return a; } -CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) { size_t i = 0; cJSON *n = NULL; diff --git a/cJSON.h b/cJSON.h index 42c1cc61..0ecd179e 100644 --- a/cJSON.h +++ b/cJSON.h @@ -213,7 +213,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); /* Append item to the specified array/object. */ CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); From bcc91ecbc37c68390f3c9339cb51428c30dd2b1e Mon Sep 17 00:00:00 2001 From: Julian Ste <31321934+julian-st@users.noreply.github.com> Date: Sat, 19 Oct 2019 13:53:21 +0200 Subject: [PATCH 183/307] initilize variables in print_number --- cJSON.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index 85e8ba64..9dfaa241 100644 --- a/cJSON.c +++ b/cJSON.c @@ -487,9 +487,9 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out double d = item->valuedouble; int length = 0; size_t i = 0; - unsigned char number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ unsigned char decimal_point = get_decimal_point(); - double test; + double test = 0.0; if (output_buffer == NULL) { From ec8d2f9c2e9de7524f9ddd78d39605d5fc6987ef Mon Sep 17 00:00:00 2001 From: randy408 Date: Mon, 21 Oct 2019 15:27:47 +0200 Subject: [PATCH 184/307] convert fuzz target to c89, optimize --- fuzzing/CMakeLists.txt | 2 +- ...son_read_fuzzer.cc => cjson_read_fuzzer.c} | 28 ++++++++----------- fuzzing/fuzz_main.c | 4 +-- fuzzing/ossfuzz.sh | 4 +-- 4 files changed, 16 insertions(+), 22 deletions(-) rename fuzzing/{cjson_read_fuzzer.cc => cjson_read_fuzzer.c} (77%) diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index 84278e8c..587368d0 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -28,6 +28,6 @@ if (ENABLE_FUZZING) endif() if(ENABLE_CJSON_TEST) - ADD_EXECUTABLE(fuzz_main fuzz_main.c) + ADD_EXECUTABLE(fuzz_main fuzz_main.c cjson_read_fuzzer.c) TARGET_LINK_LIBRARIES(fuzz_main cjson) endif() \ No newline at end of file diff --git a/fuzzing/cjson_read_fuzzer.cc b/fuzzing/cjson_read_fuzzer.c similarity index 77% rename from fuzzing/cjson_read_fuzzer.cc rename to fuzzing/cjson_read_fuzzer.c index 4ec43220..b2692edd 100644 --- a/fuzzing/cjson_read_fuzzer.cc +++ b/fuzzing/cjson_read_fuzzer.c @@ -4,9 +4,8 @@ #include "../cJSON.h" -#ifdef __cplusplus -extern "C" -#endif +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); /* required by C89 */ + int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { cJSON *json; @@ -17,6 +16,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) if(size <= offset) return 0; + if(data[size-1] != '\0') return 0; if(data[0] != '1' && data[0] != '0') return 0; if(data[1] != '1' && data[1] != '0') return 0; if(data[2] != '1' && data[2] != '0') return 0; @@ -27,19 +27,9 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) formatted = data[2] == '1' ? 1 : 0; buffered = data[3] == '1' ? 1 : 0; - copied = (unsigned char*)malloc(size); - if(copied == NULL) return 0; - - memcpy(copied, data, size); - copied[size-1] = '\0'; - - json = cJSON_ParseWithOpts((const char*)copied + offset, NULL, require_termination); + json = cJSON_ParseWithOpts((const char*)data + offset, NULL, require_termination); - if(json == NULL) - { - free(copied); - return 0; - } + if(json == NULL) return 0; if(buffered) { @@ -62,11 +52,17 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) if(minify) { + copied = (unsigned char*)malloc(size); + if(copied == NULL) return 0; + + memcpy(copied, data, size); + cJSON_Minify((char*)copied + offset); + + free(copied); } cJSON_Delete(json); - free(copied); return 0; } diff --git a/fuzzing/fuzz_main.c b/fuzzing/fuzz_main.c index e004115f..09dc1565 100644 --- a/fuzzing/fuzz_main.c +++ b/fuzzing/fuzz_main.c @@ -2,9 +2,7 @@ #include #include -int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); /* required by C90 */ - -#include "cjson_read_fuzzer.cc" +int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); /* required by C89 */ /* fuzz target entry point, works without libFuzzer */ diff --git a/fuzzing/ossfuzz.sh b/fuzzing/ossfuzz.sh index 8de60e4a..fe4bf160 100644 --- a/fuzzing/ossfuzz.sh +++ b/fuzzing/ossfuzz.sh @@ -8,8 +8,8 @@ cd build cmake -DBUILD_SHARED_LIBS=OFF -DENABLE_CJSON_TEST=OFF .. make -j$(nproc) -$CXX $CXXFLAGS -std=c++11 -I. \ - $SRC/cjson/fuzzing/cjson_read_fuzzer.cc \ +$CC $CFLAGS -std=c89 -I. \ + $SRC/cjson/fuzzing/cjson_read_fuzzer.c \ -o $OUT/cjson_read_fuzzer \ $LIB_FUZZING_ENGINE $SRC/cjson/build/libcjson.a From 6b728982f2073ea334ad436ebb5dae92486e0812 Mon Sep 17 00:00:00 2001 From: Randy Date: Tue, 22 Oct 2019 12:45:13 +0200 Subject: [PATCH 185/307] ossfuzz.sh: fix permission bits --- fuzzing/ossfuzz.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 fuzzing/ossfuzz.sh diff --git a/fuzzing/ossfuzz.sh b/fuzzing/ossfuzz.sh old mode 100644 new mode 100755 From 73b0e739d0cfc7036ef36c2736970032605eb6c7 Mon Sep 17 00:00:00 2001 From: Randy Date: Tue, 22 Oct 2019 13:32:41 +0200 Subject: [PATCH 186/307] fuzz: add support for compiling with c++ compiler --- fuzzing/cjson_read_fuzzer.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fuzzing/cjson_read_fuzzer.c b/fuzzing/cjson_read_fuzzer.c index b2692edd..e9f733d1 100644 --- a/fuzzing/cjson_read_fuzzer.c +++ b/fuzzing/cjson_read_fuzzer.c @@ -2,6 +2,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #include "../cJSON.h" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); /* required by C89 */ @@ -66,3 +70,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) return 0; } + +#ifdef __cplusplus +} +#endif \ No newline at end of file From 49a0ede475c9042a868f15718fad911f7423597a Mon Sep 17 00:00:00 2001 From: Randy Date: Tue, 22 Oct 2019 13:37:41 +0200 Subject: [PATCH 187/307] ossfuzz: build with c++ compiler --- fuzzing/ossfuzz.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fuzzing/ossfuzz.sh b/fuzzing/ossfuzz.sh index fe4bf160..a2da64bf 100755 --- a/fuzzing/ossfuzz.sh +++ b/fuzzing/ossfuzz.sh @@ -8,8 +8,7 @@ cd build cmake -DBUILD_SHARED_LIBS=OFF -DENABLE_CJSON_TEST=OFF .. make -j$(nproc) -$CC $CFLAGS -std=c89 -I. \ - $SRC/cjson/fuzzing/cjson_read_fuzzer.c \ +$CXX $CXXFLAGS $SRC/cjson/fuzzing/cjson_read_fuzzer.c -I. \ -o $OUT/cjson_read_fuzzer \ $LIB_FUZZING_ENGINE $SRC/cjson/build/libcjson.a From a417b183c6661a41f78a4ff039ad8a01321cdcf5 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Tue, 29 Oct 2019 12:47:36 +0800 Subject: [PATCH 188/307] add new line to endif --- fuzzing/CMakeLists.txt | 3 ++- fuzzing/cjson_read_fuzzer.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index 587368d0..1166000d 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -30,4 +30,5 @@ endif() if(ENABLE_CJSON_TEST) ADD_EXECUTABLE(fuzz_main fuzz_main.c cjson_read_fuzzer.c) TARGET_LINK_LIBRARIES(fuzz_main cjson) -endif() \ No newline at end of file +endif() + diff --git a/fuzzing/cjson_read_fuzzer.c b/fuzzing/cjson_read_fuzzer.c index e9f733d1..aa9c7ba7 100644 --- a/fuzzing/cjson_read_fuzzer.c +++ b/fuzzing/cjson_read_fuzzer.c @@ -73,4 +73,5 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + From de99175cd0892828dcd0838a78fdf5c6ccde2866 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Tue, 29 Oct 2019 14:21:16 +0800 Subject: [PATCH 189/307] fix rmdir error (#401) * fix rmdir error --- Makefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 8209959b..3994b50d 100644 --- a/Makefile +++ b/Makefile @@ -141,9 +141,8 @@ uninstall-cjson: uninstall-utils $(RM) $(INSTALL_LIBRARY_PATH)/$(CJSON_SHARED) $(RM) $(INSTALL_LIBRARY_PATH)/$(CJSON_SHARED_VERSION) $(RM) $(INSTALL_LIBRARY_PATH)/$(CJSON_SHARED_SO) - rmdir $(INSTALL_LIBRARY_PATH) $(RM) $(INSTALL_INCLUDE_PATH)/cJSON.h - rmdir $(INSTALL_INCLUDE_PATH) + #cJSON_Utils uninstall-utils: $(RM) $(INSTALL_LIBRARY_PATH)/$(UTILS_SHARED) @@ -151,7 +150,11 @@ uninstall-utils: $(RM) $(INSTALL_LIBRARY_PATH)/$(UTILS_SHARED_SO) $(RM) $(INSTALL_INCLUDE_PATH)/cJSON_Utils.h -uninstall: uninstall-utils uninstall-cjson +remove-dir: + $(if $(wildcard $(INSTALL_LIBRARY_PATH)/*.*),,rmdir $(INSTALL_LIBRARY_PATH)) + $(if $(wildcard $(INSTALL_INCLUDE_PATH)/*.*),,rmdir $(INSTALL_INCLUDE_PATH)) + +uninstall: uninstall-utils uninstall-cjson remove-dir clean: $(RM) $(CJSON_OBJ) $(UTILS_OBJ) #delete object files From bb059dc2e1dbcc47c6e2a932f762c390c8aaf45e Mon Sep 17 00:00:00 2001 From: Alanscut Date: Tue, 29 Oct 2019 15:48:11 +0800 Subject: [PATCH 190/307] add uninstall target in cmake --- CMakeLists.txt | 3 +++ library_config/uninstall.cmake | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 library_config/uninstall.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index f9779631..34ad39f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -253,6 +253,9 @@ if(ENABLE_CJSON_TEST) DEPENDS ${TEST_CJSON}) endif() +#Create the uninstall target +add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${PROJECT_SOURCE_DIR}/library_config/uninstall.cmake") + # Enable the use of locales option(ENABLE_LOCALES "Enable the use of locales" ON) if(ENABLE_LOCALES) diff --git a/library_config/uninstall.cmake b/library_config/uninstall.cmake new file mode 100644 index 00000000..e751ec47 --- /dev/null +++ b/library_config/uninstall.cmake @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 2.8.5) + +set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") + +if(NOT EXISTS ${MANIFEST}) + message(FATAL_ERROR "Cannot find install mainfest: ${MANIFEST}") +endif() + +file(STRINGS ${MANIFEST} files) +foreach(file ${files}) + if(EXISTS ${file} OR IS_SYMLINK ${file}) + message(STATUS "Removing: ${file}") + + execute_process(COMMAND rm -f ${file} + RESULT_VARIABLE result + OUTPUT_QUIET + ERROR_VARIABLE stderr + ERROR_STRIP_TRAILING_WHITESPACE + ) + + if(NOT ${result} EQUAL 0) + message(FATAL_ERROR "${stderr}") + endif() + else() + message(STATUS "Does-not-exist: ${file}") + endif() +endforeach(file) From 44547317756f1d3b5d6ee05b49c6b1d577b31fda Mon Sep 17 00:00:00 2001 From: Alanscut Date: Tue, 29 Oct 2019 16:14:22 +0800 Subject: [PATCH 191/307] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 06b0de9f..7c6ffaf7 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ Run this command in the directory with the source code and it will automatically make all ``` -If you want, you can install the compiled library to your system using `make install`. By default it will install the headers in `/usr/local/include/cjson` and the libraries in `/usr/local/lib`. But you can change this behavior by setting the `PREFIX` and `DESTDIR` variables: `make PREFIX=/usr DESTDIR=temp install`. +If you want, you can install the compiled library to your system using `make install`. By default it will install the headers in `/usr/local/include/cjson` and the libraries in `/usr/local/lib`. But you can change this behavior by setting the `PREFIX` and `DESTDIR` variables: `make PREFIX=/usr DESTDIR=temp install`. And uninstall them with: `make PREFIX=/usr DESTDIR=temp uninstall`. ### Including cJSON If you installed it via CMake or the Makefile, you can include cJSON like this: From 4755aea8377fd69202db235d4f4a49440c8a2270 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Fri, 1 Nov 2019 11:30:14 +0800 Subject: [PATCH 192/307] fix make failed in mac os --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3994b50d..0e58d5ce 100644 --- a/Makefile +++ b/Makefile @@ -101,7 +101,7 @@ $(CJSON_SHARED_VERSION): $(CJSON_OBJ) $(CC) -shared -o $@ $< $(CJSON_SO_LDFLAG) $(LDFLAGS) #cJSON_Utils $(UTILS_SHARED_VERSION): $(UTILS_OBJ) - $(CC) -shared -o $@ $< $(UTILS_SO_LDFLAG) $(LDFLAGS) + $(CC) -shared -o $@ $< $(CJSON_OBJ) $(UTILS_SO_LDFLAG) $(LDFLAGS) #objects #cJSON From c64854b26edb9760fd5fb6fcbc5b6d7aa3b61236 Mon Sep 17 00:00:00 2001 From: rolegic <8974088+rolegic@users.noreply.github.com> Date: Fri, 15 Nov 2019 15:43:43 +0100 Subject: [PATCH 193/307] Fixed different argument between declaration and definition --- cJSON.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cJSON.c b/cJSON.c index 8a775082..eeb5c51a 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1199,20 +1199,20 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON return (char*)p.buffer; } -CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) { printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - if ((len < 0) || (buf == NULL)) + if ((length < 0) || (buffer == NULL)) { return false; } - p.buffer = (unsigned char*)buf; - p.length = (size_t)len; + p.buffer = (unsigned char*)buffer; + p.length = (size_t)length; p.offset = 0; p.noalloc = true; - p.format = fmt; + p.format = format; p.hooks = global_hooks; return print_value(item, &p); @@ -2290,12 +2290,12 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) return item; } -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) { cJSON *item = cJSON_New_Item(&global_hooks); if(item) { - item->type = b ? cJSON_True : cJSON_False; + item->type = boolean ? cJSON_True : cJSON_False; } return item; From 446ff0d6cc58de3380ce39f506cb858ca2d2947f Mon Sep 17 00:00:00 2001 From: Alanscut Date: Wed, 27 Nov 2019 11:08:35 +0800 Subject: [PATCH 194/307] fix issue#327 --- tests/print_number.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/print_number.c b/tests/print_number.c index f2385f3b..3fbf9cb6 100644 --- a/tests/print_number.c +++ b/tests/print_number.c @@ -27,6 +27,8 @@ static void assert_print_number(const char *expected, double input) { unsigned char printed[1024]; + unsigned char new_buffer[26]; + unsigned int i = 0; cJSON item[1]; printbuffer buffer = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; buffer.buffer = printed; @@ -34,11 +36,29 @@ static void assert_print_number(const char *expected, double input) buffer.offset = 0; buffer.noalloc = true; buffer.hooks = global_hooks; + buffer.buffer = new_buffer; memset(item, 0, sizeof(item)); + memset(new_buffer, 0, sizeof(new_buffer)); cJSON_SetNumberValue(item, input); - TEST_ASSERT_TRUE_MESSAGE(print_number(item, &buffer), "Failed to print number."); + + /* In MinGW or visual studio(before 2015),the exponten is represented using three digits,like:"1e-009","1e+017" + * remove extra "0" to output "1e-09" or "1e+17",which makes testcase PASS */ + for(i = 0;i 3 && new_buffer[i] =='0') + { + if((new_buffer[i-3] =='e' && new_buffer[i-2] == '-' && new_buffer[i] =='0') ||(new_buffer[i-2] =='e' && new_buffer[i-1] =='+')) + { + while(new_buffer[i] !='\0') + { + new_buffer[i] = new_buffer[i+1]; + i++; + } + } + } + } TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, buffer.buffer, "Printed number is not as expected."); } From f3b6ad15f0282e8f6ed31e7169d893bb8630ff68 Mon Sep 17 00:00:00 2001 From: Erez Oxman Date: Thu, 28 Nov 2019 14:15:44 +0200 Subject: [PATCH 195/307] Added blank lines in Readme.md Added blank lines before list items and headings. This change creates consistency between different markdown parsers. There's no difference in the output of Github flavored markdown. See https://babelmark.github.io/ --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 7c6ffaf7..c50b1351 100644 --- a/README.md +++ b/README.md @@ -80,11 +80,13 @@ philosophy as JSON itself. Simple, dumb, out of the way. There are several ways to incorporate cJSON into your project. #### copying the source + Because the entire library is only one C file and one header file, you can just copy `cJSON.h` and `cJSON.c` to your projects source and start using it. cJSON is written in ANSI C (C89) in order to support as many platforms and compilers as possible. #### CMake + With CMake, cJSON supports a full blown build system. This way you get the most features. CMake with an equal or higher version than 2.8.5 is supported. With CMake it is recommended to do an out of tree build, meaning the compiled files are put in a directory separate from the source files. So in order to build cJSON with CMake on a Unix platform, make a `build` directory and run CMake inside it. ``` @@ -102,6 +104,7 @@ make And install it with `make install` if you want. By default it installs the headers `/usr/local/include/cjson` and the libraries to `/usr/local/lib`. It also installs files for pkg-config to make it easier to detect and use an existing installation of CMake. And it installs CMake config files, that can be used by other CMake based projects to discover the library. You can change the build process with a list of different options that you can pass to CMake. Turn them on with `On` and off with `Off`: + * `-DENABLE_CJSON_TEST=On`: Enable building the tests. (on by default) * `-DENABLE_CJSON_UTILS=On`: Enable building cJSON_Utils. (off by default) * `-DENABLE_TARGET_EXPORT=On`: Enable the export of CMake targets. Turn off if it makes problems. (on by default) @@ -127,6 +130,7 @@ make DESTDIR=$pkgdir install On Windows CMake is usually used to create a Visual Studio solution file by running it inside the Developer Command Prompt for Visual Studio, for exact steps follow the official documentation from CMake and Microsoft and use the online search engine of your choice. The descriptions of the the options above still generally apply, although not all of them work on Windows. #### Makefile + **NOTE:** This Method is deprecated. Use CMake if at all possible. Makefile support is limited to fixing bugs. If you don't have CMake available, but still have GNU make. You can use the makefile to build cJSON: @@ -140,6 +144,7 @@ make all If you want, you can install the compiled library to your system using `make install`. By default it will install the headers in `/usr/local/include/cjson` and the libraries in `/usr/local/lib`. But you can change this behavior by setting the `PREFIX` and `DESTDIR` variables: `make PREFIX=/usr DESTDIR=temp install`. And uninstall them with: `make PREFIX=/usr DESTDIR=temp uninstall`. ### Including cJSON + If you installed it via CMake or the Makefile, you can include cJSON like this: ```c @@ -171,6 +176,7 @@ An item of this type represents a JSON value. The type is stored in `type` as a To check the type of an item, use the corresponding `cJSON_Is...` function. It does a `NULL` check followed by a type check and returns a boolean value if the item is of this type. The type can be one of the following: + * `cJSON_Invalid` (check with `cJSON_IsInvalid`): Represents an invalid item that doesn't contain any value. You automatically have this type if you set the item to all zero bytes. * `cJSON_False` (check with `cJSON_IsFalse`): Represents a `false` boolean value. You can also check for boolean values in general with `cJSON_IsBool`. * `cJSON_True` (check with `cJSON_IsTrue`): Represents a `true` boolean value. You can also check for boolean values in general with `cJSON_IsBool`. @@ -182,6 +188,7 @@ The type can be one of the following: * `cJSON_Raw` (check with `cJSON_IsRaw`): Represents any kind of JSON that is stored as a zero terminated array of characters in `valuestring`. This can be used, for example, to avoid printing the same static JSON over and over again to save performance. cJSON will never create this type when parsing. Also note that cJSON doesn't check if it is valid JSON. Additionally there are the following two flags: + * `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not it's children/valuestring. * `cJSON_StringIsConst`: This means that `string` points to a constant string. This means that `cJSON_Delete` and other functions will not try to deallocate `string`. @@ -193,6 +200,7 @@ Note that you have to delete them at some point, otherwise you will get a memory **Important**: If you have added an item to an array or an object already, you **mustn't** delete it with `cJSON_Delete`. Adding it to an array or object transfers its ownership so that when that array or object is deleted, it gets deleted as well. #### Basic types + * **null** is created with `cJSON_CreateNull` * **booleans** are created with `cJSON_CreateTrue`, `cJSON_CreateFalse` or `cJSON_CreateBool` * **numbers** are created with `cJSON_CreateNumber`. This will set both `valuedouble` and `valueint`. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` are used for `valueint` @@ -272,6 +280,7 @@ If you have a rough idea of how big your resulting string will be, you can use ` These dynamic buffer allocations can be completely avoided by using `cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)`. It takes a buffer to a pointer to print to and it's length. If the length is reached, printing will fail and it returns `0`. In case of success, `1` is returned. Note that you should provide 5 bytes more than is actually needed, because cJSON is not 100% accurate in estimating if the provided memory is enough. ### Example + In this example we want to build and parse the following JSON: ```json @@ -295,7 +304,9 @@ In this example we want to build and parse the following JSON: ``` #### Printing + Let's build the above JSON and print it to a string: + ```c //create a monitor with a list of supported resolutions //NOTE: Returns a heap allocated string, you are required to free it after use. @@ -373,6 +384,7 @@ end: ``` Alternatively we can use the `cJSON_Add...ToObject` helper functions to make our lifes a little easier: + ```c //NOTE: Returns a heap allocated string, you are required to free it after use. char *create_monitor_with_helpers(void) @@ -428,6 +440,7 @@ end: ``` #### Parsing + In this example we will parse a JSON in the above format and check if the monitor supports a Full HD resolution while printing some diagnostic output: ```c @@ -514,6 +527,7 @@ cJSON doesn't support arrays and objects that are nested too deeply because this In general cJSON is **not thread safe**. However it is thread safe under the following conditions: + * `cJSON_GetErrorPtr` is never used (the `return_parse_end` parameter of `cJSON_ParseWithOpts` can be used instead) * `cJSON_InitHooks` is only ever called before using cJSON in any threads. * `setlocale` is never called before all calls to cJSON functions have returned. From 500a9db81bca54027ce8de2ce42b48fa89782e78 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 5 Dec 2019 11:05:07 +0800 Subject: [PATCH 196/307] fix memory leak mentioned in issue 414 --- cJSON_Utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 7df4db2a..b890d176 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -216,6 +216,7 @@ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const obje if (child_index > ULONG_MAX) { cJSON_free(target_pointer); + cJSON_free(full_pointer); return NULL; } sprintf((char*)full_pointer, "/%lu%s", (unsigned long)child_index, target_pointer); /* / */ From 98ecc0245a9c40de96a8b6285621ec5e5eae8c01 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Fri, 6 Dec 2019 15:32:45 +0800 Subject: [PATCH 197/307] revert R_CFLAGS --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5be36daa..08fcc22e 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ else endif PIC_FLAGS = -fPIC -R_CFLAGS = -fPIC -std=c89 -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 -Wcast-qual -Wc++-compat -Wundef -Wswitch-default -Wconversion -Wfloat-equal $(CFLAGS) +R_CFLAGS = $(PIC_FLAGS) -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 -Wcast-qual -Wc++-compat -Wundef -Wswitch-default -Wconversion -Wfloat-equal $(CFLAGS) uname := $(shell sh -c 'uname -s 2>/dev/null || echo false') From 1f970e7db36f5dc61946f5a3fbc38ada88c43464 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Fri, 6 Dec 2019 17:11:12 +0800 Subject: [PATCH 198/307] fix double comparison --- tests/readme_examples.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/readme_examples.c b/tests/readme_examples.c index 1ab1b139..80ea8aa1 100644 --- a/tests/readme_examples.c +++ b/tests/readme_examples.c @@ -202,7 +202,7 @@ static int supports_full_hd(const char * const monitor) goto end; } - if ((width->valuedouble == 1920) && (height->valuedouble == 1080)) + if (compare_double(width->valuedouble, 1920) && compare_double(height->valuedouble, 1080)) { status = 1; goto end; From c06d8264d010186c3ac98fd1eaccf9b2ba735728 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Fri, 6 Dec 2019 18:16:27 +0800 Subject: [PATCH 199/307] improve compare_double function --- cJSON.c | 2 +- cJSON.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cJSON.c b/cJSON.c index 77ca7d37..e71d22f1 100644 --- a/cJSON.c +++ b/cJSON.c @@ -483,7 +483,7 @@ static void update_offset(printbuffer * const buffer) /* securely comparison of floating-point variables */ static cJSON_bool compare_double(double a, double b) { - return (fabs(a - b) <= a * CJSON_DOUBLE_PRECIION); + return (fabs(a - b) <= CJSON_DOUBLE_PRECISION); } /* Render the number nicely from the given item into a string. */ diff --git a/cJSON.h b/cJSON.h index b896151a..2c535628 100644 --- a/cJSON.h +++ b/cJSON.h @@ -138,8 +138,8 @@ typedef int cJSON_bool; #endif /* Precision of double variables comparison */ -#ifndef CJSON_DOUBLE_PRECIION -#define CJSON_DOUBLE_PRECIION .00001 +#ifndef CJSON_DOUBLE_PRECISION +#define CJSON_DOUBLE_PRECISION .0000000000000001 #endif /* returns the version of cJSON as a string */ From ea3a6dcd69cc77ad652f4fde97accf7b30f2f40b Mon Sep 17 00:00:00 2001 From: ChenYuan Date: Sat, 7 Dec 2019 20:24:07 +0800 Subject: [PATCH 200/307] Update cJSON_Utils.c fix typo --- cJSON_Utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 214c78d8..805a9d4a 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -109,7 +109,7 @@ static int compare_strings(const unsigned char *string1, const unsigned char *st /* securely comparison of floating-point variables */ static cJSON_bool compare_double(double a, double b) { - return (fabs(a - b) <= a * CJSON_DOUBLE_PRECIION); + return (fabs(a - b) <= a * CJSON_DOUBLE_PRECISION); } From 4e3335618f4bf9583838dc254427f2307c5879e2 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Mon, 9 Dec 2019 10:36:45 +0800 Subject: [PATCH 201/307] improve compare_double --- cJSON_Utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 805a9d4a..1cbd80af 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -109,7 +109,7 @@ static int compare_strings(const unsigned char *string1, const unsigned char *st /* securely comparison of floating-point variables */ static cJSON_bool compare_double(double a, double b) { - return (fabs(a - b) <= a * CJSON_DOUBLE_PRECISION); + return (fabs(a - b) <= CJSON_DOUBLE_PRECISION); } From ea532cdd61a7adcece63caf0e691152130d3faf1 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Fri, 29 Nov 2019 16:10:41 +0800 Subject: [PATCH 202/307] update CHANGELOG.md --- CHANGELOG.md | 347 ++++++++++++++++++++++++++------------------------- 1 file changed, 174 insertions(+), 173 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4afe782d..2ec6cb40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,119 +1,117 @@ -1.7.12 +1.7.12 (May 17, 2019) ====== Fixes: ------ -* Fix infinite loop in `cJSON_Minify` (potential Denial of Service), thanks @Alanscut for reporting. See #354 -* Fix link error for Visual Studio. Thanks @tan-wei, see #352 -* Undefine `true` and `false` for `cJSON_Utils` before redefining them. Thanks @raiden00pl, see #347 +* Fix infinite loop in `cJSON_Minify` (potential Denial of Service). Thanks @Alanscut for reporting, see [#354](https://github.com/DaveGamble/cJSON/issues/354) +* Fix link error for Visual Studio. Thanks @tan-wei, see [#352](https://github.com/DaveGamble/cJSON/pull/352). +* Undefine `true` and `false` for `cJSON_Utils` before redefining them. Thanks @raiden00pl, see [#347](https://github.com/DaveGamble/cJSON/pull/347). - -1.7.11 +1.7.11 (Apr 15, 2019) ====== Fixes: ------ -* Fix a bug where cJSON_Minify could overflow it's buffer, both reading and writing. This is a security issue. (see #338). Big thanks @bigric3 for reporting. -* Unset `true` and `false` macros before setting them if they exist. See #339, thanks @raiden00pl for reporting +* Fix a bug where cJSON_Minify could overflow it's buffer, both reading and writing. This is a security issue, see [#338](https://github.com/DaveGamble/cJSON/issues/338). Big thanks @bigric3 for reporting. +* Unset `true` and `false` macros before setting them if they exist. See [#339](https://github.com/DaveGamble/cJSON/issues/339), thanks @raiden00pl for reporting -1.7.10 +1.7.10 (Dec 21, 2018) ====== Fixes: ------ -* Fix package config file for `libcjson`. Thanks @shiluotang for reporting (#321) -* Correctly split lists in `cJSON_Utils`'s merge sort. Thanks @andysCaplin for the fix (#322) +* Fix package config file for `libcjson`. Thanks @shiluotang for reporting [#321](https://github.com/DaveGamble/cJSON/issues/321) +* Correctly split lists in `cJSON_Utils`'s merge sort. Thanks @andysCaplin for the fix [#322](https://github.com/DaveGamble/cJSON/issues/322) -1.7.9 +1.7.9 (Dec 16, 2018) ===== Fixes: ------ -* Fix a bug where `cJSON_GetObjectItemCaseSensitive` would pass a nullpointer to `strcmp` when called on an array (#315). Thanks @yuweol for reporting. -* Fix error in `cJSON_Utils` where the case sensitivity was not respected (#317). Thanks @yuta-oxo for fixing. -* Fix some warnings detected by the Visual Studio Static Analyzer (#307). Thanks @bnason-nf +* Fix a bug where `cJSON_GetObjectItemCaseSensitive` would pass a nullpointer to `strcmp` when called on an array, see [#315](https://github.com/DaveGamble/cJSON/issues/315). Thanks @yuweol for reporting. +* Fix error in `cJSON_Utils` where the case sensitivity was not respected, see [#317](https://github.com/DaveGamble/cJSON/pull/317). Thanks @yuta-oxo for fixing. +* Fix some warnings detected by the Visual Studio Static Analyzer, see [#307](https://github.com/DaveGamble/cJSON/pull/307). Thanks @bnason-nf -1.7.8 -===== +1.7.8 (Sep 22, 2018) +====== Fixes: ------ -* cJSON now works with the `__stdcall` calling convention on Windows, see #295, thanks @zhindes for contributing +* cJSON now works with the `__stdcall` calling convention on Windows, see [#295](https://github.com/DaveGamble/cJSON/pull/295), thanks @zhindes for contributing -1.7.7 +1.7.7 (May 22, 2018) ===== Fixes: ------ -* Fix a memory leak when realloc fails (see #267), thanks @AlfieDeng for reporting -* Fix a typo in the header file (see #266), thanks @zhaozhixu +* Fix a memory leak when realloc fails, see [#267](https://github.com/DaveGamble/cJSON/issues/267), thanks @AlfieDeng for reporting +* Fix a typo in the header file, see [#266](https://github.com/DaveGamble/cJSON/pull/266), thanks @zhaozhixu -1.7.6 +1.7.6 (Apr 13, 2018) ===== Fixes: ------ -* Add `SONAME` to the ELF files built by the Makefile (see #252), thanks @YanhaoMo for reporting -* Add include guards and `extern "C"` to `cJSON_Utils.h` (see #256), thanks @daschfg for reporting +* Add `SONAME` to the ELF files built by the Makefile, see [#252](https://github.com/DaveGamble/cJSON/issues/252), thanks @YanhaoMo for reporting +* Add include guards and `extern "C"` to `cJSON_Utils.h`, see [#256](https://github.com/DaveGamble/cJSON/issues/256), thanks @daschfg for reporting Other changes: --------------- * Mark the Makefile as deprecated in the README. -1.7.5 +1.7.5 (Mar 23, 2018) ===== Fixes: ------ -* Fix a bug in the JSON Patch implementation of `cJSON Utils` (see #251), thanks @bobkocisko. +* Fix a bug in the JSON Patch implementation of `cJSON Utils`, see [#251](https://github.com/DaveGamble/cJSON/pull/251), thanks @bobkocisko. -1.7.4 +1.7.4 (Mar 3, 2018) ===== Fixes: ------ -* Fix potential use after free if the `string` parameter to `cJSON_AddItemToObject` is an alias of the `string` property of the object that is added (#248). Thanks @hhallen for reporting. +* Fix potential use after free if the `string` parameter to `cJSON_AddItemToObject` is an alias of the `string` property of the object that is added,see [#248](https://github.com/DaveGamble/cJSON/issues/248). Thanks @hhallen for reporting. -1.7.3 +1.7.3 (Feb 8, 2018) ===== Fixes: ------ -* Fix potential double free, thanks @projectgus for reporting (see #241) +* Fix potential double free, thanks @projectgus for reporting [#241](https://github.com/DaveGamble/cJSON/issues/241) -1.7.2 +1.7.2 (Feb 6, 2018) ===== Fixes: ------ -* Fix the use of GNUInstallDirs variables and the pkgconfig file. Thanks @zeerd for reporting (see #240) +* Fix the use of GNUInstallDirs variables and the pkgconfig file. Thanks @zeerd for reporting [#240](https://github.com/DaveGamble/cJSON/pull/240) -1.7.1 +1.7.1 (Jan 10, 2018) ===== Fixes: ------ -* Fixed an Off-By-One error that could lead to an out of bounds write. Thanks @liuyunbin for reporting (see #230) -* Fixed two errors with buffered printing. Thanks @liuyunbin for reporting (see #230) +* Fixed an Off-By-One error that could lead to an out of bounds write. Thanks @liuyunbin for reporting [#230](https://github.com/DaveGamble/cJSON/issues/230) +* Fixed two errors with buffered printing. Thanks @liuyunbin for reporting [#230](https://github.com/DaveGamble/cJSON/issues/230) -1.7.0 +1.7.0 (Dec 31, 2017) ===== Features: --------- -* Large rewrite of the documentation, see #215 +* Large rewrite of the documentation, see [#215](https://github.com/DaveGamble/cJSON/pull/215) * Added the `cJSON_GetStringValue` function * Added the `cJSON_CreateStringReference` function * Added the `cJSON_CreateArrayReference` function * Added the `cJSON_CreateObjectReference` function -* The `cJSON_Add...ToObject` macros are now functions that return a pointer to the added item, see #226 +* The `cJSON_Add...ToObject` macros are now functions that return a pointer to the added item, see [#226](https://github.com/DaveGamble/cJSON/pull/226) Fixes: ------ -* Fix a problem with `GNUInstallDirs` in the CMakeLists.txt, thanks @yangfl, see #210 -* Fix linking the tests when building as static library, see #213 -* New overrides for the CMake option `BUILD_SHARED_LIBS`, see #207 +* Fix a problem with `GNUInstallDirs` in the CMakeLists.txt, thanks @yangfl, see [#210](https://github.com/DaveGamble/cJSON/pull/210) +* Fix linking the tests when building as static library, see [#213](https://github.com/DaveGamble/cJSON/issues/213) +* New overrides for the CMake option `BUILD_SHARED_LIBS`, see [#207](https://github.com/DaveGamble/cJSON/issues/207) Other Changes: -------------- -* Readme: Explain how to include cJSON, see #211 -* Removed some trailing spaces in the code, thanks @yangfl, see#212 +* Readme: Explain how to include cJSON, see [#211](https://github.com/DaveGamble/cJSON/pull/211) +* Removed some trailing spaces in the code, thanks @yangfl, see [#212](https://github.com/DaveGamble/cJSON/pull/212) * Updated [Unity](https://github.com/ThrowTheSwitch/Unity) and [json-patch-tests](https://github.com/json-patch/json-patch-tests) -1.6.0 +1.6.0 (Oct 9, 2017) ===== Features: --------- -* You can now build cJSON as both shared and static library at once with CMake using `-DBUILD_SHARED_AND_STATIC_LIBS=On`, see #178 -* UTF-8 byte order marks are now ignored, see #184 -* Locales can now be disabled with the option `-DENABLE_LOCALES=Off`, see #202, thanks @Casperinous +* You can now build cJSON as both shared and static library at once with CMake using `-DBUILD_SHARED_AND_STATIC_LIBS=On`, see [#178](https://github.com/DaveGamble/cJSON/issues/178) +* UTF-8 byte order marks are now ignored, see [#184](https://github.com/DaveGamble/cJSON/issues/184) +* Locales can now be disabled with the option `-DENABLE_LOCALES=Off`, see [#202](https://github.com/DaveGamble/cJSON/issues/202), thanks @Casperinous * Better support for MSVC and Visual Studio Other Changes: @@ -122,75 +120,78 @@ Other Changes: * More number printing tests. * Continuous integration testing with AppVeyor (semi automatic at this point), thanks @simon-p-r -1.5.9 +1.5.9 (Sep 8, 2017) ===== -* Set the global error pointer even if `return_parse_end` is passed to `cJSON_ParseWithOpts`. See #200, thanks @rmallins +Fixes: +------ +* Set the global error pointer even if `return_parse_end` is passed to `cJSON_ParseWithOpts`, see [#200](https://github.com/DaveGamble/cJSON/pull/200), thanks @rmallins -1.5.8 +1.5.8 (Aug 21, 2017) ===== -* Fix `make test` in the Makefile, thanks @YanhaoMo for reporting this (#195) +Fixes: +------ +* Fix `make test` in the Makefile, thanks @YanhaoMo for reporting this [#195](https://github.com/DaveGamble/cJSON/issues/195) -1.5.7 +1.5.7 (Jul 13, 2017) ===== Fixes: ------ -* Fix a bug where realloc failing would return a pointer to an invalid memory address. This is a security issue as it could potentially be used by an attacker to write to arbitrary memory addresses. (see #189), fixed in (954d61e5e7cb9dc6c480fc28ac1cdceca07dd5bd), big thanks @timothyjohncarney for reporting this issue -* Fix a spelling mistake in the AFL fuzzer dictionary (#185), thanks @jwilk +* Fix a bug where realloc failing would return a pointer to an invalid memory address. This is a security issue as it could potentially be used by an attacker to write to arbitrary memory addresses, see [#189](https://github.com/DaveGamble/cJSON/issues/189), fixed in [954d61e](https://github.com/DaveGamble/cJSON/commit/954d61e5e7cb9dc6c480fc28ac1cdceca07dd5bd), big thanks @timothyjohncarney for reporting this issue +* Fix a spelling mistake in the AFL fuzzer dictionary, see [#185](https://github.com/DaveGamble/cJSON/pull/185), thanks @jwilk -1.5.6 +1.5.6 (Jun 28, 2017) ===== Fixes: ------ -* Make cJSON a lot more tolerant about passing NULL pointers to its functions, it should now fail safely instead of dereferencing the pointer. (#183) Thanks @msichal for reporting #182 +* Make cJSON a lot more tolerant about passing NULL pointers to its functions, it should now fail safely instead of dereferencing the pointer, see [#183](https://github.com/DaveGamble/cJSON/pull/183). Thanks @msichal for reporting [#182](https://github.com/DaveGamble/cJSON/issues/182) -1.5.5 +1.5.5 (Jun 15, 2017) ===== Fixes: ------ -* Fix pointers to nested arrays in cJSON_Utils (9abe75e072050f34732a7169740989a082b65134) -* Fix an error with case sensitivity handling in cJSON_Utils (b9cc911831b0b3e1bb72f142389428e59f882b38) -* Fix cJSON_Compare for arrays that are prefixes of the other and objects that are a subset of the other (03ba72faec115160d1f3aea5582d9b6af5d3e473) See #180, thanks @zhengqb for reporting +* Fix pointers to nested arrays in cJSON_Utils, see [9abe](https://github.com/DaveGamble/cJSON/commit/9abe75e072050f34732a7169740989a082b65134) +* Fix an error with case sensitivity handling in cJSON_Utils, see [b9cc911](https://github.com/DaveGamble/cJSON/commit/b9cc911831b0b3e1bb72f142389428e59f882b38) +* Fix cJSON_Compare for arrays that are prefixes of the other and objects that are a subset of the other, see [03ba72f](https://github.com/DaveGamble/cJSON/commit/03ba72faec115160d1f3aea5582d9b6af5d3e473) and [#180](https://github.com/DaveGamble/cJSON/issues/180), thanks @zhengqb for reporting -1.5.4 -===== +1.5.4 (Jun 5, 2017) +====== Fixes: ------ -* Fix build with GCC 7.1.1 and optimization level `-O2` (bfbd8fe0d85f1dd21e508748fc10fc4c27cc51be) +* Fix build with GCC 7.1.1 and optimization level `-O2`, see [bfbd8fe](https://github.com/DaveGamble/cJSON/commit/bfbd8fe0d85f1dd21e508748fc10fc4c27cc51be) Other Changes: -------------- * Update [Unity](https://github.com/ThrowTheSwitch/Unity) to 3b69beaa58efc41bbbef70a32a46893cae02719d -1.5.3 +1.5.3 (May 23, 2017) ===== Fixes: ------ -* Fix `cJSON_ReplaceItemInObject` not keeping the name of an item (#174) +* Fix `cJSON_ReplaceItemInObject` not keeping the name of an item, see [#174](https://github.com/DaveGamble/cJSON/issues/174) -1.5.2 +1.5.2 (May 10, 2017) ===== Fixes: ------ -* Fix a reading buffer overflow in `parse_string` (a167d9e381e5c84bc03de4e261757b031c0c690d) -* Fix compiling with -Wcomma (186cce3ece6ce6dfcb58ac8b2a63f7846c3493ad) -* Remove leftover attribute from tests (b537ca70a35680db66f1f5b8b437f7114daa699a) +* Fix a reading buffer overflow in `parse_string`, see [a167d9e](https://github.com/DaveGamble/cJSON/commit/a167d9e381e5c84bc03de4e261757b031c0c690d) +* Fix compiling with -Wcomma, see [186cce3](https://github.com/DaveGamble/cJSON/commit/186cce3ece6ce6dfcb58ac8b2a63f7846c3493ad) +* Remove leftover attribute from tests, see [b537ca7](https://github.com/DaveGamble/cJSON/commit/b537ca70a35680db66f1f5b8b437f7114daa699a) -1.5.1 +1.5.1 (May 6, 2017) ===== Fixes: ------ -* Add gcc version guard to the Makefile (#164), thanks @juvasquezg -* Fix incorrect free in `cJSON_Utils` if custom memory allocator is used (#166), thanks @prefetchnta +* Add gcc version guard to the Makefile, see [#164](https://github.com/DaveGamble/cJSON/pull/164), thanks @juvasquezg +* Fix incorrect free in `cJSON_Utils` if custom memory allocator is used, see [#166](https://github.com/DaveGamble/cJSON/pull/166), thanks @prefetchnta -1.5.0 +1.5.0 (May 2, 2017) ===== Features: ---------- -* cJSON finally prints numbers without losing precision (#153) thanks @DeboraG -* `cJSON_Compare` recursively checks if two cJSON items contain the same values (#148) -* Provide case sensitive versions of every function where it matters (#158, #159) +* cJSON finally prints numbers without losing precision, see [#153](https://github.com/DaveGamble/cJSON/pull/153), thanks @DeboraG +* `cJSON_Compare` recursively checks if two cJSON items contain the same values, see [#148](https://github.com/DaveGamble/cJSON/pull/148) +* Provide case sensitive versions of every function where it matters, see [#158](https://github.com/DaveGamble/cJSON/pull/158) and [#159](https://github.com/DaveGamble/cJSON/pull/159) * Added `cJSON_ReplaceItemViaPointer` and `cJSON_DetachItemViaPointer` -* Added `cJSON_free` and `cJSON_malloc` that expose the internal configured memory allocators. (02a05eea4e6ba41811f130b322660bea8918e1a0) +* Added `cJSON_free` and `cJSON_malloc` that expose the internal configured memory allocators. see [02a05ee](https://github.com/DaveGamble/cJSON/commit/02a05eea4e6ba41811f130b322660bea8918e1a0) Enhancements: @@ -204,7 +205,7 @@ Enhancements: Fixes: ------ -* Fix some warnings with the Microsoft compiler (#139) thanks @PawelWMS +* Fix some warnings with the Microsoft compiler, see [#139](https://github.com/DaveGamble/cJSON/pull/139), thanks @PawelWMS * Fix several bugs in cJSON_Utils, mostly found with [json-patch-tests](https://github.com/json-patch/json-patch-tests) * Prevent a stack overflow by specifying a maximum nesting depth `CJSON_NESTING_LIMIT` @@ -212,180 +213,180 @@ Other Changes: -------------- * Move generated files in the `library_config` subdirectory. -1.4.7 +1.4.7 (Apr 19, 2017) ===== Fixes: ------ -* Fix `cJSONUtils_ApplyPatches`, it was completely broken and apparently nobody noticed (or at least reported it) (075a06f40bdc4f836c7dd7cad690d253a57cfc50) -* Fix inconsistent prototype for `cJSON_GetObjectItemCaseSensitive` (51d3df6c9f7b56b860c8fb24abe7bab255cd4fa9) thanks @PawelWMS +* Fix `cJSONUtils_ApplyPatches`, it was completely broken and apparently nobody noticed (or at least reported it), see [075a06f](https://github.com/DaveGamble/cJSON/commit/075a06f40bdc4f836c7dd7cad690d253a57cfc50) +* Fix inconsistent prototype for `cJSON_GetObjectItemCaseSensitive`, see [51d3df6](https://github.com/DaveGamble/cJSON/commit/51d3df6c9f7b56b860c8fb24abe7bab255cd4fa9), thanks @PawelWMS -1.4.6 +1.4.6 (Apr 9, 2017) ===== Fixes: ------ * Several corrections in the README * Making clear that `valueint` should not be written to -* Fix overflow detection in `ensure` (2683d4d9873df87c4bdccc523903ddd78d1ad250) -* Fix a potential null pointer dereference in cJSON_Utils (795c3acabed25c9672006b2c0f40be8845064827) -* Replace incorrect `sizeof('\0')` with `sizeof("")` (84237ff48e69825c94261c624eb0376d0c328139) -* Add caveats section to the README (50b3c30dfa89830f8f477ce33713500740ac3b79) -* Make cJSON locale independent (#146) Thanks @peterh for reporting -* Fix compiling without CMake with MSVC (#147) Thanks @dertuxmalwieder for reporting +* Fix overflow detection in `ensure`, see [2683d4d](https://github.com/DaveGamble/cJSON/commit/2683d4d9873df87c4bdccc523903ddd78d1ad250) +* Fix a potential null pointer dereference in cJSON_Utils, see [795c3ac](https://github.com/DaveGamble/cJSON/commit/795c3acabed25c9672006b2c0f40be8845064827) +* Replace incorrect `sizeof('\0')` with `sizeof("")`, see [84237ff](https://github.com/DaveGamble/cJSON/commit/84237ff48e69825c94261c624eb0376d0c328139) +* Add caveats section to the README, see [50b3c30](https://github.com/DaveGamble/cJSON/commit/50b3c30dfa89830f8f477ce33713500740ac3b79) +* Make cJSON locale independent, see [#146](https://github.com/DaveGamble/cJSON/pull/146), Thanks @peterh for reporting +* Fix compiling without CMake with MSVC, see [#147](https://github.com/DaveGamble/cJSON/pull/147), Thanks @dertuxmalwieder for reporting -1.4.5 +1.4.5 (Mar 28, 2017) ===== Fixes: ------ -* Fix bug in `cJSON_SetNumberHelper`, thanks @mmkeeper (#138 ef34500693e8c4a2849d41a4bd66fd19c9ec46c2) +* Fix bug in `cJSON_SetNumberHelper`, thanks @mmkeeper, see [#138](https://github.com/DaveGamble/cJSON/issues/138) and [ef34500](https://github.com/DaveGamble/cJSON/commit/ef34500693e8c4a2849d41a4bd66fd19c9ec46c2) * Workaround for internal compiler error in GCC 5.4.0 and 6.3.1 on x86 (2f65e80a3471d053fdc3f8aed23d01dd1782a5cb [GCC bugreport](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80097)) -1.4.4 +1.4.4 (Mar 24, 2017) ===== Fixes: --------- -* Fix a theoretical integer overflow, (not sure if it is possible on actual hardware) e58f7ec027d00b7cdcbf63e518c1b5268b29b3da -* Fix an off by one error (cc84a446be20cc283bafdc4d94c050ba1111ac02), thanks @gatzka -* Double check the offset of the print buffer in `ensure` (1934059554b9a0971e00f79e96900f422cfdd114) +------ +* Fix a theoretical integer overflow, (not sure if it is possible on actual hardware), see [e58f7ec](https://github.com/DaveGamble/cJSON/commit/e58f7ec027d00b7cdcbf63e518c1b5268b29b3da) +* Fix an off by one error, see [cc84a44](https://github.com/DaveGamble/cJSON/commit/cc84a446be20cc283bafdc4d94c050ba1111ac02), thanks @gatzka +* Double check the offset of the print buffer in `ensure`, see [1934059](https://github.com/DaveGamble/cJSON/commit/1934059554b9a0971e00f79e96900f422cfdd114) Improvements: -------------- -* Add a note in the header about required buffer size when using `cJSON_PrintPreallocated` (4bfb88009342fb568295a7f6dc4b7fee74fbf022) +* Add a note in the header about required buffer size when using `cJSON_PrintPreallocated`, see [4bfb8800](https://github.com/DaveGamble/cJSON/commit/4bfb88009342fb568295a7f6dc4b7fee74fbf022) -1.4.3 +1.4.3 (Mar 19, 2017) ===== Fixes: ------ -* Fix compilation of the tests on 32 bit PowerPC and potentially other systems (4ec6e76ea2eec16f54b58e8c95b4c734e59481e4) -* Fix compilation with old GCC compilers (4.3+ were tested) (227d3398d6b967879761ebe02c1b63dbd6ea6e0d, 466eb8e3f8a65080f2b3ca4a79ab7b72bd539dba), see also #126 +* Fix compilation of the tests on 32 bit PowerPC and potentially other systems, see [4ec6e76](https://github.com/DaveGamble/cJSON/commit/4ec6e76ea2eec16f54b58e8c95b4c734e59481e4) +* Fix compilation with old GCC compilers (4.3+ were tested), see [227d33](https://github.com/DaveGamble/cJSON/commit/227d3398d6b967879761ebe02c1b63dbd6ea6e0d), [466eb8e](https://github.com/DaveGamble/cJSON/commit/466eb8e3f8a65080f2b3ca4a79ab7b72bd539dba), see also [#126](https://github.com/DaveGamble/cJSON/issues/126) -1.4.2 +1.4.2 (Mar 16, 2017) ===== Fixes: ------ -* Fix minimum required cmake version (30e1e7af7c63db9b55f5a3cda977a6c032f0b132) -* Fix detection of supported compiler flags (76e5296d0d05ceb3018a9901639e0e171b44a557) -* Run `cJSON_test` and `cJSON_test_utils` along with unity tests (c597601cf151a757dcf800548f18034d4ddfe2cb) +* Fix minimum required cmake version, see [30e1e7a](https://github.com/DaveGamble/cJSON/commit/30e1e7af7c63db9b55f5a3cda977a6c032f0b132) +* Fix detection of supported compiler flags, see [76e5296](https://github.com/DaveGamble/cJSON/commit/76e5296d0d05ceb3018a9901639e0e171b44a557) +* Run `cJSON_test` and `cJSON_test_utils` along with unity tests, see [c597601](https://github.com/DaveGamble/cJSON/commit/c597601cf151a757dcf800548f18034d4ddfe2cb) -1.4.1 +1.4.1 (Mar 16, 2017) ===== -Fix: Make `print_number` abort with a failure in out of memory situations (cf1842dc6f64c49451a022308b4415e4d468be0a) +Fixes: +------ +* Make `print_number` abort with a failure in out of memory situations, see [cf1842](https://github.com/DaveGamble/cJSON/commit/cf1842dc6f64c49451a022308b4415e4d468be0a) -1.4.0 +1.4.0 (Mar 4, 2017) ===== Features -------- -* Functions to check the type of an item (#120) -* Use dllexport on windows and fvisibility on Unix systems for public functions (#116), thanks @mjerris -* Remove trailing zeroes from printed numbers (#123) -* Expose the internal boolean type `cJSON_bool` in the header (2d3520e0b9d0eb870e8886e8a21c571eeddbb310) +* Functions to check the type of an item, see [#120](https://github.com/DaveGamble/cJSON/pull/120) +* Use dllexport on windows and fvisibility on Unix systems for public functions, see [#116](https://github.com/DaveGamble/cJSON/pull/116), thanks @mjerris +* Remove trailing zeroes from printed numbers, see [#123](https://github.com/DaveGamble/cJSON/pull/123) +* Expose the internal boolean type `cJSON_bool` in the header, see [2d3520e](https://github.com/DaveGamble/cJSON/commit/2d3520e0b9d0eb870e8886e8a21c571eeddbb310) Fixes ------ -* Fix handling of NULL pointers in `cJSON_ArrayForEach` (b47d0e34caaef298edfb7bd09a72cfff21d231ff) -* Make it compile with GCC 7 (fix -Wimplicit-fallthrough warning) (9d07917feb1b613544a7513d19233d4c851ad7ad) +* Fix handling of NULL pointers in `cJSON_ArrayForEach`, see [b47d0e3](https://github.com/DaveGamble/cJSON/commit/b47d0e34caaef298edfb7bd09a72cfff21d231ff) +* Make it compile with GCC 7 (fix -Wimplicit-fallthrough warning), see [9d07917](https://github.com/DaveGamble/cJSON/commit/9d07917feb1b613544a7513d19233d4c851ad7ad) Other Improvements ------------------- -* internally use realloc if available (#110) -* builtin support for fuzzing with [afl](http://lcamtuf.coredump.cx/afl/) (#111) -* unit tests for the print functions (#112) -* Always use buffered printing (#113) -* simplify the print functions (#114) -* Add the compiler flags `-Wdouble-conversion`, `-Wparentheses` and `-Wcomma` (#122) +* internally use realloc if available ([#110](https://github.com/DaveGamble/cJSON/pull/110)) +* builtin support for fuzzing with [afl](http://lcamtuf.coredump.cx/afl/) ([#111](https://github.com/DaveGamble/cJSON/pull/111)) +* unit tests for the print functions ([#112](https://github.com/DaveGamble/cJSON/pull/112)) +* Always use buffered printing ([#113](https://github.com/DaveGamble/cJSON/pull/113)) +* simplify the print functions ([#114](https://github.com/DaveGamble/cJSON/pull/114)) +* Add the compiler flags `-Wdouble-conversion`, `-Wparentheses` and `-Wcomma` ([#122](https://github.com/DaveGamble/cJSON/pull/122)) -1.3.2 +1.3.2 (Mar 1, 2017) ===== -Fix: ----- -- Don't build the unity library if testing is disabled ( #121 ). Thanks @ffontaine +Fixes: +------ +* Don't build the unity library if testing is disabled, see [#121](https://github.com/DaveGamble/cJSON/pull/121). Thanks @ffontaine -1.3.1 +1.3.1 (Feb 27, 2017) ===== -Bugfix release that fixes an out of bounds read #118. This shouldn't have any security implications. +Fixes: +------ +* Bugfix release that fixes an out of bounds read, see [#118](https://github.com/DaveGamble/cJSON/pull/118). This shouldn't have any security implications. -1.3.0 +1.3.0 (Feb 17, 2017) ===== This release includes a lot of rework in the parser and includes the Cunity unit testing framework, as well as some fixes. I increased the minor version number because there were quite a lot of internal changes. Features: ---------- -- New type for cJSON structs: `cJSON_Invalid` (#108) +* New type for cJSON structs: `cJSON_Invalid`, see [#108](https://github.com/DaveGamble/cJSON/pull/108) Fixes: ------ -- runtime checks for a lot of potential integer overflows -- fix incorrect return in cJSON_PrintBuffered (cf9d57d56cac21fc59465b8d26cf29bf6d2a87b3) -- fix several potential issues found by [Coverity](https://scan.coverity.com/projects/cjson) -- fix potentially undefined behavior when assigning big numbers to `valueint` (41e2837df1b1091643aff073f2313f6ff3cc10f4) - - Numbers exceeding `INT_MAX` or lower than `INT_MIN` will be explicitly assigned to `valueint` as `INT_MAX` and `INT_MIN` respectively (saturation on overflow). - - fix the `cJSON_SetNumberValue` macro (87f77274de6b3af00fb9b9a7f3b900ef382296c2), this slightly changes the behavior, see commit message +* runtime checks for a lot of potential integer overflows +* fix incorrect return in cJSON_PrintBuffered [cf9d57d](https://github.com/DaveGamble/cJSON/commit/cf9d57d56cac21fc59465b8d26cf29bf6d2a87b3) +* fix several potential issues found by [Coverity](https://scan.coverity.com/projects/cjson) +* fix potentially undefined behavior when assigning big numbers to `valueint` ([41e2837](https://github.com/DaveGamble/cJSON/commit/41e2837df1b1091643aff073f2313f6ff3cc10f4)) + * Numbers exceeding `INT_MAX` or lower than `INT_MIN` will be explicitly assigned to `valueint` as `INT_MAX` and `INT_MIN` respectively (saturation on overflow). + * fix the `cJSON_SetNumberValue` macro ([87f7727](https://github.com/DaveGamble/cJSON/commit/87f77274de6b3af00fb9b9a7f3b900ef382296c2)), this slightly changes the behavior, see commit message Introduce unit tests -------------------- -Started writing unit tests with the [Cunity](https://github.com/ThrowTheSwitch/Unity) testing framework. Currently this covers the parser functions. +* Started writing unit tests with the [Cunity](https://github.com/ThrowTheSwitch/Unity) testing framework. Currently this covers the parser functions. Also: -- Support for running the tests with [Valgrind](http://valgrind.org) -- Support for compiling the tests with [AddressSanitizer](https://github.com/google/sanitizers) and [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html). -- `travis.yml` file for running unit tests on travis. (not enabled for the repository yet though #102) +* Support for running the tests with [Valgrind](http://valgrind.org) +* Support for compiling the tests with [AddressSanitizer](https://github.com/google/sanitizers) and [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html). +* `travis.yml` file for running unit tests on travis. (not enabled for the repository yet though [#102](https://github.com/DaveGamble/cJSON/issues/102) Simplifications --------------- After having unit tests for the parser function in place, I started refactoring the parser functions (as well as others) and making them easier to read and maintain. -- Use `strtod` from the standard library for parsing numbers (074766997246481dfc72bfa78f07898a2716473f) -- Use goto-fail in several parser functions (#100) -- Rewrite/restructure all of the parsing functions to be easier to understand and have less code paths doing the same as another. (#109) -- Simplify the buffer allocation strategy to always doubling the needed amount (9f6fa94c91a87b71e4c6868dbf2ce431a48517b0) -- Combined `cJSON_AddItemToObject` and `cJSON_AddItemToObjectCS` to one function (cf862d0fed7f9407e4b046d78d3d8050d2080d12) +* Use `strtod` from the standard library for parsing numbers ([0747669](https://github.com/DaveGamble/cJSON/commit/074766997246481dfc72bfa78f07898a2716473f)) +* Use goto-fail in several parser functions ([#100](https://github.com/DaveGamble/cJSON/pull/100)) +* Rewrite/restructure all of the parsing functions to be easier to understand and have less code paths doing the same as another. ([#109](https://github.com/DaveGamble/cJSON/pull/109)) +* Simplify the buffer allocation strategy to always doubling the needed amount ([9f6fa94](https://github.com/DaveGamble/cJSON/commit/9f6fa94c91a87b71e4c6868dbf2ce431a48517b0)) +* Combined `cJSON_AddItemToObject` and `cJSON_AddItemToObjectCS` to one function ([cf862d](https://github.com/DaveGamble/cJSON/commit/cf862d0fed7f9407e4b046d78d3d8050d2080d12)) Other changes ------------- -- Prevent the usage of incompatible C and header versions via preprocessor directive (123bb1af7bfae41d805337fef4b41045ef6c7d25) -- Let CMake automatically detect compiler flags -- Add new compiler flags (`-Wundef`, `-Wswitch-default`, `-Wconversion`, `-fstack-protector-strong`) (#98) -- Change internal sizes from `int` to `size_t` (ecd5678527a6bc422da694e5be9e9979878fe6a0) -- Change internal strings from `char*` to `unsigned char*` (28b9ba4334e0f7309e867e874a31f395c0ac2474) -- Add `const` in more places +* Prevent the usage of incompatible C and header versions via preprocessor directive ([123bb1](https://github.com/DaveGamble/cJSON/commit/123bb1af7bfae41d805337fef4b41045ef6c7d25)) +* Let CMake automatically detect compiler flags +* Add new compiler flags (`-Wundef`, `-Wswitch-default`, `-Wconversion`, `-fstack-protector-strong`) ([#98](https://github.com/DaveGamble/cJSON/pull/98)) +* Change internal sizes from `int` to `size_t` ([ecd5678](https://github.com/DaveGamble/cJSON/commit/ecd5678527a6bc422da694e5be9e9979878fe6a0)) +* Change internal strings from `char*` to `unsigned char*` ([28b9ba4](https://github.com/DaveGamble/cJSON/commit/28b9ba4334e0f7309e867e874a31f395c0ac2474)) +* Add `const` in more places -1.2.1 +1.2.1 (Jan 31, 2017) ===== Fixes: ------ -- Fixes a potential null pointer dereference in cJSON_Utils, discovered using clang's static analyzer by @bnason-nf (#96) +* Fixes a potential null pointer dereference in cJSON_Utils, discovered using clang's static analyzer by @bnason-nf, see [#96](https://github.com/DaveGamble/cJSON/issues/96) -1.2.0 +1.2.0 (Jan 9, 2017) ===== Features: --------- -- Add a new type of cJSON item for raw JSON and support printing it. Thanks @loigu (#65, #90) +* Add a new type of cJSON item for raw JSON and support printing it. Thanks @loigu, see [#65](https://github.com/DaveGamble/cJSON/pull/65), [#90](https://github.com/DaveGamble/cJSON/pull/90) Fixes: ------ -- Compiler warning if const is casted away, Thanks @gatzka (#83) -- Fix compile error with strict-overflow on PowerPC, (#85) -- Fix typo in the README, thanks @MicroJoe (#88) -- Add compile flag for compatibility with C++ compilers +* Compiler warning if const is casted away, Thanks @gatzka, see [#83](https://github.com/DaveGamble/cJSON/pull/83) +* Fix compile error with strict-overflow on PowerPC, see [#85](https://github.com/DaveGamble/cJSON/issues/85) +* Fix typo in the README, thanks @MicroJoe, see [#88](https://github.com/DaveGamble/cJSON/pull/88) +* Add compile flag for compatibility with C++ compilers -1.1.0 +1.1.0 (Dec 6, 2016) ===== -- Add a function `cJSON_PrintPreallocated` to print to a preallocated buffer, thanks @ChisholmKyle (#72) -- More compiler warnings when using Clang or GCC, thanks @gatzka (#75, #78) -- fixed a memory leak in `cJSON_Duplicate`, thanks @alperakcan (#81) -- fix the `ENABLE_CUSTOM_COMPILER_FLAGS` cmake option +* Add a function `cJSON_PrintPreallocated` to print to a preallocated buffer, thanks @ChisholmKyle, see [#72](https://github.com/DaveGamble/cJSON/pull/72) +* More compiler warnings when using Clang or GCC, thanks @gatzka, see [#75](https://github.com/DaveGamble/cJSON/pull/75), [#78](https://github.com/DaveGamble/cJSON/pull/78) +* fixed a memory leak in `cJSON_Duplicate`, thanks @alperakcan, see [#81](https://github.com/DaveGamble/cJSON/pull/81) +* fix the `ENABLE_CUSTOM_COMPILER_FLAGS` cmake option -1.0.2 +1.0.2 (Nov 25, 2016) ===== -Rename internal boolean type, see #71. +* Rename internal boolean type, see [#71](https://github.com/DaveGamble/cJSON/issues/71). -1.0.1 +1.0.1 (Nov 20, 2016) ===== Small bugfix release. -- Fixes a bug with the use of the cJSON structs type in cJSON_Utils, see d47339e2740360e6e0994527d5e4752007480f3a -- improve code readability -- initialize all variables +* Fixes a bug with the use of the cJSON structs type in cJSON_Utils, see [d47339e](https://github.com/DaveGamble/cJSON/commit/d47339e2740360e6e0994527d5e4752007480f3a) +* improve code readability +* initialize all variables -1.0.0 +1.0.0 (Nov 17, 2016) ===== This is the first official versioned release of cJSON. It provides an API version for the shared library and improved Makefile and CMake build files. From fa8b4545522a7b9031246158f12164ed5698fbf5 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 16 Jan 2020 17:10:52 +0800 Subject: [PATCH 203/307] correct mistake --- cJSON_Utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 1cbd80af..79e052be 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1144,7 +1144,7 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa switch (from->type & 0xFF) { case cJSON_Number: - if ((from->valueint != to->valueint) || (compare_double(from->valuedouble, to->valuedouble))) + if ((from->valueint != to->valueint) || !compare_double(from->valuedouble, to->valuedouble)) { compose_patch(patches, (const unsigned char*)"replace", path, NULL, to); } From 74b2f038371d0359c11bf082c603e7aa11d360b2 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Sat, 18 Jan 2020 23:02:55 +0800 Subject: [PATCH 204/307] remove annoying float-equal option --- CMakeLists.txt | 1 - cJSON.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b64ad369..34ad39f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,6 @@ if (ENABLE_CUSTOM_COMPILER_FLAGS) -Wmissing-variable-declarations -Wused-but-marked-unused -Wswitch-enum - -Wfloat-equal ) elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") # Disable warning c4001 - nonstandard extension 'single line comment' was used diff --git a/cJSON.c b/cJSON.c index e71d22f1..bc95cde6 100644 --- a/cJSON.c +++ b/cJSON.c @@ -503,7 +503,7 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out } /* This checks for NaN and Infinity */ - if (!compare_double(d * 0, 0)) + if ((d * 0) != 0) { length = sprintf((char*)number_buffer, "null"); } From cc78050ff4bd75935c7e8007308359d10eee1401 Mon Sep 17 00:00:00 2001 From: NancyLi1013 Date: Sat, 18 Jan 2020 22:47:13 -0800 Subject: [PATCH 205/307] Add vcpkg installation instructions --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index c50b1351..325a4606 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,19 @@ make DESTDIR=$pkgdir install On Windows CMake is usually used to create a Visual Studio solution file by running it inside the Developer Command Prompt for Visual Studio, for exact steps follow the official documentation from CMake and Microsoft and use the online search engine of your choice. The descriptions of the the options above still generally apply, although not all of them work on Windows. +### Building cJSON Using vcpkg + +You can download and install cJSON using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: +``` +git clone https://github.com/Microsoft/vcpkg.git +cd vcpkg +./bootstrap-vcpkg.sh +./vcpkg integrate install +vcpkg install snappy +``` + +The Snappy port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. + #### Makefile **NOTE:** This Method is deprecated. Use CMake if at all possible. Makefile support is limited to fixing bugs. From ada21691830277bfcdb41d547c35820b9d28cbe9 Mon Sep 17 00:00:00 2001 From: NancyLi1013 Date: Sat, 18 Jan 2020 23:08:01 -0800 Subject: [PATCH 206/307] Update changes --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 325a4606..fe537789 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ make DESTDIR=$pkgdir install On Windows CMake is usually used to create a Visual Studio solution file by running it inside the Developer Command Prompt for Visual Studio, for exact steps follow the official documentation from CMake and Microsoft and use the online search engine of your choice. The descriptions of the the options above still generally apply, although not all of them work on Windows. -### Building cJSON Using vcpkg +#### Building cJSON - Using vcpkg You can download and install cJSON using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: ``` @@ -137,10 +137,10 @@ git clone https://github.com/Microsoft/vcpkg.git cd vcpkg ./bootstrap-vcpkg.sh ./vcpkg integrate install -vcpkg install snappy +vcpkg install cjson ``` -The Snappy port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. +The cJSON port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. #### Makefile From f790e17b6cecef030c4eda811149d238c2085fcf Mon Sep 17 00:00:00 2001 From: Alanscut Date: Sun, 19 Jan 2020 15:23:48 +0800 Subject: [PATCH 207/307] update content in README --- README.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index fe537789..9a6226fe 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Ultralightweight JSON parser in ANSI C. * [Copying the source](#copying-the-source) * [CMake](#cmake) * [Makefile](#makefile) + * [Vcpkg](#Vcpkg) * [Including cJSON](#including-cjson) * [Data Structure](#data-structure) * [Working with the data structure](#working-with-the-data-structure) @@ -129,19 +130,6 @@ make DESTDIR=$pkgdir install On Windows CMake is usually used to create a Visual Studio solution file by running it inside the Developer Command Prompt for Visual Studio, for exact steps follow the official documentation from CMake and Microsoft and use the online search engine of your choice. The descriptions of the the options above still generally apply, although not all of them work on Windows. -#### Building cJSON - Using vcpkg - -You can download and install cJSON using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: -``` -git clone https://github.com/Microsoft/vcpkg.git -cd vcpkg -./bootstrap-vcpkg.sh -./vcpkg integrate install -vcpkg install cjson -``` - -The cJSON port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. - #### Makefile **NOTE:** This Method is deprecated. Use CMake if at all possible. Makefile support is limited to fixing bugs. @@ -156,6 +144,19 @@ make all If you want, you can install the compiled library to your system using `make install`. By default it will install the headers in `/usr/local/include/cjson` and the libraries in `/usr/local/lib`. But you can change this behavior by setting the `PREFIX` and `DESTDIR` variables: `make PREFIX=/usr DESTDIR=temp install`. And uninstall them with: `make PREFIX=/usr DESTDIR=temp uninstall`. +#### Vcpkg + +You can download and install cJSON using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: +``` +git clone https://github.com/Microsoft/vcpkg.git +cd vcpkg +./bootstrap-vcpkg.sh +./vcpkg integrate install +vcpkg install cjson +``` + +The cJSON port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. + ### Including cJSON If you installed it via CMake or the Makefile, you can include cJSON like this: From 895b9ad344358467e9b136bbb868290c0e3752ed Mon Sep 17 00:00:00 2001 From: "dm8.kim" Date: Tue, 11 Feb 2020 13:25:02 +0900 Subject: [PATCH 208/307] formatting README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9a6226fe..85c06f58 100644 --- a/README.md +++ b/README.md @@ -324,7 +324,7 @@ Let's build the above JSON and print it to a string: ```c //create a monitor with a list of supported resolutions //NOTE: Returns a heap allocated string, you are required to free it after use. -char* create_monitor(void) +char *create_monitor(void) { const unsigned int resolution_numbers[3][2] = { {1280, 720}, @@ -434,7 +434,7 @@ char *create_monitor_with_helpers(void) goto end; } - if(cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL) + if (cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL) { goto end; } @@ -443,7 +443,8 @@ char *create_monitor_with_helpers(void) } string = cJSON_Print(monitor); - if (string == NULL) { + if (string == NULL) + { fprintf(stderr, "Failed to print monitor.\n"); } From e8077d01500279a7b45b8cd7a0ae94ea7ad5748a Mon Sep 17 00:00:00 2001 From: xiaomianhehe Date: Tue, 18 Feb 2020 11:54:23 +0800 Subject: [PATCH 209/307] use prev pointer when array do adding (#430) * use prev pointer when array do adding --- cJSON.c | 37 ++++++++++++++++++++++++++++--------- tests/misc_tests.c | 2 +- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/cJSON.c b/cJSON.c index bc95cde6..a198d668 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1871,22 +1871,34 @@ static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) } child = array->child; - + /* + * To find the last item int array quickly, we use prev in array + */ if (child == NULL) { /* list is empty, start new one */ array->child = item; + item->prev = item; + item->next = NULL; } else { /* append to the end */ - while (child->next) + if (child->prev) { - child = child->next; + suffix_object(child->prev, item); + array->child->prev = item; + } + else + { + while (child->next) + { + child = child->next; + } + suffix_object(child, item); + array->child->prev = item; } - suffix_object(child, item); } - return true; } @@ -2206,14 +2218,21 @@ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON { replacement->next->prev = replacement; } - if (replacement->prev != NULL) - { - replacement->prev->next = replacement; - } + if (parent->child == item) { parent->child = replacement; } + else + { /* + * To find the last item int array quickly, we use prev in array. + * We can't modify the last item's next pointer where this item was the parent's child + */ + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + } item->next = NULL; item->prev = NULL; diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 1635fa30..95516834 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -306,7 +306,7 @@ static void cjson_replace_item_via_pointer_should_replace_items(void) /* replace beginning */ TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, beginning, &(replacements[0]))); - TEST_ASSERT_NULL(replacements[0].prev); + TEST_ASSERT_TRUE(replacements[0].prev == end); TEST_ASSERT_TRUE(replacements[0].next == middle); TEST_ASSERT_TRUE(middle->prev == &(replacements[0])); TEST_ASSERT_TRUE(array->child == &(replacements[0])); From b0e7195a749c66cdff53b0548483a8d8e5a7bd83 Mon Sep 17 00:00:00 2001 From: Square789 <46634729+Square789@users.noreply.github.com> Date: Mon, 9 Mar 2020 13:40:08 +0100 Subject: [PATCH 210/307] Spelling; "it's"->"its" --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 85c06f58..3ffd4e2c 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,7 @@ The type can be one of the following: Additionally there are the following two flags: -* `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not it's children/valuestring. +* `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not its children/valuestring. * `cJSON_StringIsConst`: This means that `string` points to a constant string. This means that `cJSON_Delete` and other functions will not try to deallocate `string`. ### Working with the data structure @@ -218,7 +218,7 @@ Note that you have to delete them at some point, otherwise you will get a memory * **null** is created with `cJSON_CreateNull` * **booleans** are created with `cJSON_CreateTrue`, `cJSON_CreateFalse` or `cJSON_CreateBool` * **numbers** are created with `cJSON_CreateNumber`. This will set both `valuedouble` and `valueint`. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` are used for `valueint` -* **strings** are created with `cJSON_CreateString` (copies the string) or with `cJSON_CreateStringReference` (directly points to the string. This means that `valuestring` won't be deleted by `cJSON_Delete` and you are responsible for it's lifetime, useful for constants) +* **strings** are created with `cJSON_CreateString` (copies the string) or with `cJSON_CreateStringReference` (directly points to the string. This means that `valuestring` won't be deleted by `cJSON_Delete` and you are responsible for its lifetime, useful for constants) #### Arrays @@ -289,9 +289,9 @@ It will allocate a string and print a JSON representation of the tree into it. O `cJSON_Print` will print with whitespace for formatting. If you want to print without formatting, use `cJSON_PrintUnformatted`. -If you have a rough idea of how big your resulting string will be, you can use `cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)`. `fmt` is a boolean to turn formatting with whitespace on and off. `prebuffer` specifies the first buffer size to use for printing. `cJSON_Print` currently uses 256 bytes for it's first buffer size. Once printing runs out of space, a new buffer is allocated and the old gets copied over before printing is continued. +If you have a rough idea of how big your resulting string will be, you can use `cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)`. `fmt` is a boolean to turn formatting with whitespace on and off. `prebuffer` specifies the first buffer size to use for printing. `cJSON_Print` currently uses 256 bytes for its first buffer size. Once printing runs out of space, a new buffer is allocated and the old gets copied over before printing is continued. -These dynamic buffer allocations can be completely avoided by using `cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)`. It takes a buffer to a pointer to print to and it's length. If the length is reached, printing will fail and it returns `0`. In case of success, `1` is returned. Note that you should provide 5 bytes more than is actually needed, because cJSON is not 100% accurate in estimating if the provided memory is enough. +These dynamic buffer allocations can be completely avoided by using `cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)`. It takes a buffer to a pointer to print to and its length. If the length is reached, printing will fail and it returns `0`. In case of success, `1` is returned. Note that you should provide 5 bytes more than is actually needed, because cJSON is not 100% accurate in estimating if the provided memory is enough. ### Example From 9034a9cd0be8f1b1441681ff57b2027a463b3329 Mon Sep 17 00:00:00 2001 From: Alan Wang <948467222@qq.com> Date: Mon, 16 Mar 2020 23:04:39 +0800 Subject: [PATCH 211/307] Revert "use prev pointer when array do adding (#430)" This reverts commit e8077d01500279a7b45b8cd7a0ae94ea7ad5748a. --- cJSON.c | 37 +++++++++---------------------------- tests/misc_tests.c | 2 +- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/cJSON.c b/cJSON.c index a198d668..bc95cde6 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1871,34 +1871,22 @@ static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) } child = array->child; - /* - * To find the last item int array quickly, we use prev in array - */ + if (child == NULL) { /* list is empty, start new one */ array->child = item; - item->prev = item; - item->next = NULL; } else { /* append to the end */ - if (child->prev) + while (child->next) { - suffix_object(child->prev, item); - array->child->prev = item; - } - else - { - while (child->next) - { - child = child->next; - } - suffix_object(child, item); - array->child->prev = item; + child = child->next; } + suffix_object(child, item); } + return true; } @@ -2218,21 +2206,14 @@ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON { replacement->next->prev = replacement; } - + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } if (parent->child == item) { parent->child = replacement; } - else - { /* - * To find the last item int array quickly, we use prev in array. - * We can't modify the last item's next pointer where this item was the parent's child - */ - if (replacement->prev != NULL) - { - replacement->prev->next = replacement; - } - } item->next = NULL; item->prev = NULL; diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 95516834..1635fa30 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -306,7 +306,7 @@ static void cjson_replace_item_via_pointer_should_replace_items(void) /* replace beginning */ TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, beginning, &(replacements[0]))); - TEST_ASSERT_TRUE(replacements[0].prev == end); + TEST_ASSERT_NULL(replacements[0].prev); TEST_ASSERT_TRUE(replacements[0].next == middle); TEST_ASSERT_TRUE(middle->prev == &(replacements[0])); TEST_ASSERT_TRUE(array->child == &(replacements[0])); From d92c0de7e8189e461546e751b84f0b1048ea6e3d Mon Sep 17 00:00:00 2001 From: Alanscut Date: Wed, 18 Mar 2020 16:04:58 +0800 Subject: [PATCH 212/307] fix encode_string_as_pointer --- cJSON_Utils.c | 3 ++- tests/old_utils_tests.c | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 79e052be..3a535b1d 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -173,13 +173,14 @@ static void encode_string_as_pointer(unsigned char *destination, const unsigned { if (source[0] == '/') { + destination[0] = '~'; destination[1] = '1'; destination++; } else if (source[0] == '~') { destination[0] = '~'; - destination[1] = '1'; + destination[1] = '0'; destination++; } else diff --git a/tests/old_utils_tests.c b/tests/old_utils_tests.c index 08da6a6d..690dbb58 100644 --- a/tests/old_utils_tests.c +++ b/tests/old_utils_tests.c @@ -90,6 +90,10 @@ static void misc_tests(void) /* Misc tests */ int numbers[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; cJSON *object = NULL; + cJSON *object1 = NULL; + cJSON *object2 = NULL; + cJSON *object3 = NULL; + cJSON *object4 = NULL; cJSON *nums = NULL; cJSON *num6 = NULL; char *pointer = NULL; @@ -112,7 +116,23 @@ static void misc_tests(void) TEST_ASSERT_EQUAL_STRING("", pointer); free(pointer); + object1 = cJSON_CreateObject(); + object2 = cJSON_CreateString("m~n"); + cJSON_AddItemToObject(object1, "m~n", object2); + pointer = cJSONUtils_FindPointerFromObjectTo(object1, object2); + TEST_ASSERT_EQUAL_STRING("/m~0n",pointer); + free(pointer); + + object3 = cJSON_CreateObject(); + object4 = cJSON_CreateString("m/n"); + cJSON_AddItemToObject(object3, "m/n", object4); + pointer = cJSONUtils_FindPointerFromObjectTo(object3, object4); + TEST_ASSERT_EQUAL_STRING("/m~1n",pointer); + free(pointer); + cJSON_Delete(object); + cJSON_Delete(object1); + cJSON_Delete(object3); } static void sort_tests(void) From fa28d82f2e9fcb975ce9977c958afcbc34adf137 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 19 Mar 2020 22:58:04 +0800 Subject: [PATCH 213/307] update contributors --- CONTRIBUTORS.md | 27 ++++++++++++++++++++++++--- README.md | 2 +- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index c6a73108..0552025d 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,20 +1,29 @@ Contributors ============ -Original Author: [Dave Gamble](https://github.com/DaveGamble) -Current Maintainer: [Max Bruckner](https://github.com/FSMaxB) +Original Author: +- [Dave Gamble](https://github.com/DaveGamble) +Current Maintainer: +- [Max Bruckner](https://github.com/FSMaxB) +- [Alan Wang](https://github.com/Alanscut) + +Contributors: * [Ajay Bhargav](https://github.com/ajaybhargav) * [Alper Akcan](https://github.com/alperakcan) +* [Andrew Tang](https://github.com/singku) * [Anton Sergeev](https://github.com/anton-sergeev) * [Benbuck Nason](https://github.com/bnason-nf) +* [Bernt Johan Damslora](https://github.com/bjda) * [Bob Kocisko](https://github.com/bobkocisko) * [Christian Schulze](https://github.com/ChristianSch) * [Casperinous](https://github.com/Casperinous) +* [ChenYuan](https://github.com/zjuchenyuan) * [Debora Grosse](https://github.com/DeboraG) * [dieyushi](https://github.com/dieyushi) * [Dōngwén Huáng (黄东文)](https://github.com/DongwenHuang) * [Donough Liu](https://github.com/ldm0) +* [Erez Oxman](https://github.com/erez-o) * Eswar Yaganti * [Evan Todd](https://github.com/etodd) * [Fabrice Fontaine](https://github.com/ffontaine) @@ -24,26 +33,38 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB) * [Jakub Wilk](https://github.com/jwilk) * [Jiri Zouhar](https://github.com/loigu) * [Jonathan Fether](https://github.com/jfether) +* [Julian Ste](https://github.com/julian-st) * [Julián Vásquez](https://github.com/juvasquezg) * [Kevin Branigan](https://github.com/kbranigan) * [Kyle Chisholm](https://github.com/ChisholmKyle) * [Linus Wallgren](https://github.com/ecksun) +* [Mateusz Szafoni](https://github.com/raiden00pl) * Mike Pontillo * [Mike Jerris](https://github.com/mjerris) * [Mike Robinson](https://github.com/mhrobinson) +* [myd7349](https://github.com/myd7349) +* [NancyLi1013](https://github.com/NancyLi1013) * Paulo Antonio Alvarez +* [Paweł Malowany](https://github.com/PawelMalowany) * [Pawel Winogrodzki](https://github.com/PawelWMS) * [prefetchnta](https://github.com/prefetchnta) * [Rafael Leal Dias](https://github.com/rafaeldias) +* [Randy](https://github.com/randy408) * [raiden00pl](https://github.com/raiden00pl) * [Robin Mallinson](https://github.com/rmallins) * [Rod Vagg](https://github.com/rvagg) * [Roland Meertens](https://github.com/rmeertens) * [Romain Porte](https://github.com/MicroJoe) +* [SANJEEV BA](https://github.com/basanjeev) +* [Sang-Heon Jeon](https://github.com/lntuition) +* [Simon Sobisch](https://github.com/GitMensch) * [Simon Ricaldone](https://github.com/simon-p-r) +* [Square789](https://github.com/Square789) * [Stephan Gatzka](https://github.com/gatzka) -* [tan-wei](https://github.com/tan-wei) +* [Vemake](https://github.com/vemakereporter) +* [Wei Tan](https://github.com/tan-wei) * [Weston Schmidt](https://github.com/schmidtw) +* [xiaomianhehe](https://github.com/xiaomianhehe) * [yangfl](https://github.com/yangfl) * [yuta-oxo](https://github.com/yuta-oxo) * [Zach Hindes](https://github.com/zhindes) diff --git a/README.md b/README.md index 3ffd4e2c..55aba581 100644 --- a/README.md +++ b/README.md @@ -558,5 +558,5 @@ cJSON supports parsing and printing JSON that contains objects that have multipl # Enjoy cJSON! - Dave Gamble (original author) -- Max Bruckner (current maintainer) +- Max Bruckner and Alan Wang (current maintainer) - and the other [cJSON contributors](CONTRIBUTORS.md) From 3ece4c893c123aa3d77f90d580cf6b0a4b3a2ad5 Mon Sep 17 00:00:00 2001 From: Alan Wang Date: Tue, 24 Mar 2020 16:17:25 +0800 Subject: [PATCH 214/307] Improve performance of adding item to array (#448) * use prev pointer when adding item to array Co-authored-by: xiaomianhehe Co-authored-by: Alanscut Date: Tue Feb 18 11:54:23 2020 +0800 * add testcase for cJSON_DeleteItemFromArray --- cJSON.c | 37 ++++++++++++++++++++++++++++--------- tests/misc_tests.c | 43 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/cJSON.c b/cJSON.c index bc95cde6..b0e744e4 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1871,20 +1871,33 @@ static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) } child = array->child; - + /* + * To find the last item in array quickly, we use prev in array + */ if (child == NULL) { /* list is empty, start new one */ array->child = item; + item->prev = item; + item->next = NULL; } else { /* append to the end */ - while (child->next) + if (child->prev) + { + suffix_object(child->prev, item); + array->child->prev = item; + } + else { - child = child->next; + while (child->next) + { + child = child->next; + } + suffix_object(child, item); + array->child->prev = item; } - suffix_object(child, item); } return true; @@ -2095,7 +2108,7 @@ CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const it return NULL; } - if (item->prev != NULL) + if (item != parent->child) { /* not the first element */ item->prev->next = item->next; @@ -2206,14 +2219,20 @@ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON { replacement->next->prev = replacement; } - if (replacement->prev != NULL) - { - replacement->prev->next = replacement; - } if (parent->child == item) { parent->child = replacement; } + else + { /* + * To find the last item in array quickly, we use prev in array. + * We can't modify the last item's next pointer where this item was the parent's child + */ + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + } item->next = NULL; item->prev = NULL; diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 1635fa30..20a5ddd6 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -255,6 +255,7 @@ static void cjson_detach_item_via_pointer_should_detach_items(void) list[3].prev = &(list[2]); list[2].prev = &(list[1]); list[1].prev = &(list[0]); + list[0].prev = &(list[3]); parent->child = &list[0]; @@ -266,7 +267,7 @@ static void cjson_detach_item_via_pointer_should_detach_items(void) /* detach beginning (list[0]) */ TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &(list[0])) == &(list[0]), "Failed to detach beginning."); TEST_ASSERT_TRUE_MESSAGE((list[0].prev == NULL) && (list[0].next == NULL), "Didn't set pointers of detached item to NULL."); - TEST_ASSERT_TRUE_MESSAGE((list[2].prev == NULL) && (parent->child == &(list[2])), "Didn't set the new beginning."); + TEST_ASSERT_TRUE_MESSAGE((list[2].prev == &(list[3])) && (parent->child == &(list[2])), "Didn't set the new beginning."); /* detach end (list[3])*/ TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &(list[3])) == &(list[3]), "Failed to detach end."); @@ -306,7 +307,7 @@ static void cjson_replace_item_via_pointer_should_replace_items(void) /* replace beginning */ TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, beginning, &(replacements[0]))); - TEST_ASSERT_NULL(replacements[0].prev); + TEST_ASSERT_TRUE(replacements[0].prev == end); TEST_ASSERT_TRUE(replacements[0].next == middle); TEST_ASSERT_TRUE(middle->prev == &(replacements[0])); TEST_ASSERT_TRUE(array->child == &(replacements[0])); @@ -346,7 +347,7 @@ static void cjson_replace_item_in_object_should_preserve_name(void) cJSON_Delete(replacement); } -static void cjson_functions_shouldnt_crash_with_null_pointers(void) +static void cjson_functions_should_not_crash_with_null_pointers(void) { char buffer[10]; cJSON *item = cJSON_CreateString("item"); @@ -549,6 +550,39 @@ static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_al cJSON_Delete(object); } +static void cjson_delete_item_from_array_should_not_broken_list_structure(void) { + const char expected_json1[] = "{\"rd\":[{\"a\":\"123\"}]}"; + const char expected_json2[] = "{\"rd\":[{\"a\":\"123\"},{\"b\":\"456\"}]}"; + const char expected_json3[] = "{\"rd\":[{\"b\":\"456\"}]}"; + char* str1 = NULL; + char* str2 = NULL; + char* str3 = NULL; + + cJSON* root = cJSON_Parse("{}"); + + cJSON* array = cJSON_AddArrayToObject(root, "rd"); + cJSON* item1 = cJSON_Parse("{\"a\":\"123\"}"); + cJSON* item2 = cJSON_Parse("{\"b\":\"456\"}"); + + cJSON_AddItemToArray(array, item1); + str1 = cJSON_PrintUnformatted(root); + TEST_ASSERT_EQUAL_STRING(expected_json1, str1); + free(str1); + + cJSON_AddItemToArray(array, item2); + str2 = cJSON_PrintUnformatted(root); + TEST_ASSERT_EQUAL_STRING(expected_json2, str2); + free(str2); + + /* this should not broken list structure */ + cJSON_DeleteItemFromArray(array, 0); + str3 = cJSON_PrintUnformatted(root); + TEST_ASSERT_EQUAL_STRING(expected_json3, str3); + free(str3); + + cJSON_Delete(root); +} + int CJSON_CDECL main(void) { UNITY_BEGIN(); @@ -565,7 +599,7 @@ int CJSON_CDECL main(void) RUN_TEST(cjson_detach_item_via_pointer_should_detach_items); RUN_TEST(cjson_replace_item_via_pointer_should_replace_items); RUN_TEST(cjson_replace_item_in_object_should_preserve_name); - RUN_TEST(cjson_functions_shouldnt_crash_with_null_pointers); + RUN_TEST(cjson_functions_should_not_crash_with_null_pointers); RUN_TEST(ensure_should_fail_on_failed_realloc); RUN_TEST(skip_utf8_bom_should_skip_bom); RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); @@ -574,6 +608,7 @@ int CJSON_CDECL main(void) 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); + RUN_TEST(cjson_delete_item_from_array_should_not_broken_list_structure); return UNITY_END(); } From 6b35f1c5bc347377ea32881914a0fe5d60e730e6 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Tue, 24 Mar 2020 22:28:15 +0800 Subject: [PATCH 215/307] add new function of setValuestringToObject --- cJSON.c | 25 +++++++++++++++++++++++++ cJSON.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/cJSON.c b/cJSON.c index b0e744e4..ff8d2b99 100644 --- a/cJSON.c +++ b/cJSON.c @@ -368,6 +368,31 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) return object->valuedouble = number; } +CJSON_PUBLIC(char*) cJSON_SetValuestringToObject(cJSON *object, const char *valuestring) +{ + size_t length = 0; + char *copy = NULL; + /* if object->valuestring is NULL, it should not set valuestring */ + if (object->valuestring == NULL) + { + return NULL; + } + length = strlen(valuestring) + sizeof(""); + copy = (char*) cJSON_malloc(length); + if (copy == NULL) + { + return NULL; + } + memcpy(copy, valuestring, length); + if (!(object->type & cJSON_IsReference) && (object->valuestring != NULL)) + { + cJSON_free(object->valuestring); + } + object->valuestring = copy; + + return copy; +} + typedef struct { unsigned char *buffer; diff --git a/cJSON.h b/cJSON.h index 2c535628..1455ece7 100644 --- a/cJSON.h +++ b/cJSON.h @@ -278,6 +278,8 @@ CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * c /* helper for the cJSON_SetNumberValue macro */ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) +/* Only takes effect when type of object is JSON_Object */ +CJSON_PUBLIC(char*) cJSON_SetValuestringToObject(cJSON *object, const char *valuestring); /* Macro for iterating over an array or object */ #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) From 4790c3c8f52cc08ad584e148c4e3d93d9d063f0c Mon Sep 17 00:00:00 2001 From: Alanscut Date: Tue, 24 Mar 2020 22:28:27 +0800 Subject: [PATCH 216/307] add testcase for cJSON_SetValuestringToObject --- tests/misc_tests.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 20a5ddd6..ba494f5c 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -550,19 +550,20 @@ static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_al cJSON_Delete(object); } -static void cjson_delete_item_from_array_should_not_broken_list_structure(void) { +static void cjson_delete_item_from_array_should_not_broken_list_structure(void) +{ const char expected_json1[] = "{\"rd\":[{\"a\":\"123\"}]}"; const char expected_json2[] = "{\"rd\":[{\"a\":\"123\"},{\"b\":\"456\"}]}"; const char expected_json3[] = "{\"rd\":[{\"b\":\"456\"}]}"; - char* str1 = NULL; - char* str2 = NULL; - char* str3 = NULL; + char *str1 = NULL; + char *str2 = NULL; + char *str3 = NULL; - cJSON* root = cJSON_Parse("{}"); + cJSON *root = cJSON_Parse("{}"); - cJSON* array = cJSON_AddArrayToObject(root, "rd"); - cJSON* item1 = cJSON_Parse("{\"a\":\"123\"}"); - cJSON* item2 = cJSON_Parse("{\"b\":\"456\"}"); + cJSON *array = cJSON_AddArrayToObject(root, "rd"); + cJSON *item1 = cJSON_Parse("{\"a\":\"123\"}"); + cJSON *item2 = cJSON_Parse("{\"b\":\"456\"}"); cJSON_AddItemToArray(array, item1); str1 = cJSON_PrintUnformatted(root); @@ -583,6 +584,31 @@ static void cjson_delete_item_from_array_should_not_broken_list_structure(void) cJSON_Delete(root); } +static void cjson_set_valuestring_to_object_should_not_leak_memory(void) +{ + cJSON *root = cJSON_Parse("{}"); + cJSON *item1 = cJSON_CreateString("valuestring could be changed safely"); + cJSON *item2 = cJSON_CreateStringReference("reference item should be freed by yourself"); + const char *newValuestring = "new valuestring which much longer than previous"; + char *returnValue = NULL; + + cJSON_AddItemToObject(root, "one", item1); + cJSON_AddItemToObject(root, "two", item2); + + /* we needn't to free the original valuestring manually */ + returnValue = cJSON_SetValuestringToObject(cJSON_GetObjectItem(root, "one"), newValuestring); + TEST_ASSERT_NOT_NULL(returnValue); + TEST_ASSERT_EQUAL_STRING(newValuestring, cJSON_GetObjectItem(root, "one")->valuestring); + + returnValue = cJSON_SetValuestringToObject(cJSON_GetObjectItem(root, "two"), newValuestring); + TEST_ASSERT_NOT_NULL(returnValue); + TEST_ASSERT_EQUAL_STRING(newValuestring, cJSON_GetObjectItem(root, "two")->valuestring); + /* we must free the memory manually when the item's type is cJSON_IsReference */ + cJSON_free(item2->valuestring); + + cJSON_Delete(root); +} + int CJSON_CDECL main(void) { UNITY_BEGIN(); @@ -609,6 +635,7 @@ int CJSON_CDECL main(void) 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); RUN_TEST(cjson_delete_item_from_array_should_not_broken_list_structure); + RUN_TEST(cjson_set_valuestring_to_object_should_not_leak_memory); return UNITY_END(); } From 34e102d0dc91d274b66b5faa434140ac90a92598 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Tue, 24 Mar 2020 22:28:35 +0800 Subject: [PATCH 217/307] update README --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 55aba581..f074b635 100644 --- a/README.md +++ b/README.md @@ -197,21 +197,22 @@ The type can be one of the following: * `cJSON_NULL` (check with `cJSON_IsNull`): Represents a `null` value. * `cJSON_Number` (check with `cJSON_IsNumber`): Represents a number value. The value is stored as a double in `valuedouble` and also in `valueint`. If the number is outside of the range of an integer, `INT_MAX` or `INT_MIN` are used for `valueint`. * `cJSON_String` (check with `cJSON_IsString`): Represents a string value. It is stored in the form of a zero terminated string in `valuestring`. -* `cJSON_Array` (check with `cJSON_IsArray`): Represent an array value. This is implemented by pointing `child` to a linked list of `cJSON` items that represent the values in the array. The elements are linked together using `next` and `prev`, where the first element has `prev == NULL` and the last element `next == NULL`. +* `cJSON_Array` (check with `cJSON_IsArray`): Represent an array value. This is implemented by pointing `child` to a linked list of `cJSON` items that represent the values in the array. The elements are linked together using `next` and `prev`, where the first element has `prev.next == NULL` and the last element `next == NULL`. * `cJSON_Object` (check with `cJSON_IsObject`): Represents an object value. Objects are stored same way as an array, the only difference is that the items in the object store their keys in `string`. * `cJSON_Raw` (check with `cJSON_IsRaw`): Represents any kind of JSON that is stored as a zero terminated array of characters in `valuestring`. This can be used, for example, to avoid printing the same static JSON over and over again to save performance. cJSON will never create this type when parsing. Also note that cJSON doesn't check if it is valid JSON. Additionally there are the following two flags: -* `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not its children/valuestring. +* `cJSON_IsReference`: Specifies that the item that `child` points to and/or `valuestring` is not owned by this item, it is only a reference. So `cJSON_Delete` and other functions will only deallocate this item, not its `child`/`valuestring`. * `cJSON_StringIsConst`: This means that `string` points to a constant string. This means that `cJSON_Delete` and other functions will not try to deallocate `string`. ### Working with the data structure For every value type there is a `cJSON_Create...` function that can be used to create an item of that type. All of these will allocate a `cJSON` struct that can later be deleted with `cJSON_Delete`. -Note that you have to delete them at some point, otherwise you will get a memory leak. -**Important**: If you have added an item to an array or an object already, you **mustn't** delete it with `cJSON_Delete`. Adding it to an array or object transfers its ownership so that when that array or object is deleted, it gets deleted as well. +Note that you have to delete them at some point, otherwise you will get a memory leak. +**Important**: If you have added an item to an array or an object already, you **mustn't** delete it with `cJSON_Delete`. Adding it to an array or object transfers its ownership so that when that array or object is deleted, +it gets deleted as well. You also could use `cJSON_SetValuestringToObject` to change a `cJSON_Object`'s `valuestring`, and you needn't to free the previous `valuestring` manually. #### Basic types From 31c7880fab5722a6fef47589c5064f7445d39f1d Mon Sep 17 00:00:00 2001 From: Alanscut Date: Wed, 25 Mar 2020 15:38:54 +0800 Subject: [PATCH 218/307] update cJSON_SetValuestring and testcase --- README.md | 2 +- cJSON.c | 18 ++++++++++-------- cJSON.h | 4 ++-- tests/misc_tests.c | 36 +++++++++++++++++++++++------------- 4 files changed, 36 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index f074b635..5480b8e3 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,7 @@ For every value type there is a `cJSON_Create...` function that can be used to c All of these will allocate a `cJSON` struct that can later be deleted with `cJSON_Delete`. Note that you have to delete them at some point, otherwise you will get a memory leak. **Important**: If you have added an item to an array or an object already, you **mustn't** delete it with `cJSON_Delete`. Adding it to an array or object transfers its ownership so that when that array or object is deleted, -it gets deleted as well. You also could use `cJSON_SetValuestringToObject` to change a `cJSON_Object`'s `valuestring`, and you needn't to free the previous `valuestring` manually. +it gets deleted as well. You also could use `cJSON_SetValuestring` to change a `cJSON_String`'s `valuestring`, and you needn't to free the previous `valuestring` manually. #### Basic types diff --git a/cJSON.c b/cJSON.c index ff8d2b99..2433de3a 100644 --- a/cJSON.c +++ b/cJSON.c @@ -368,23 +368,25 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) return object->valuedouble = number; } -CJSON_PUBLIC(char*) cJSON_SetValuestringToObject(cJSON *object, const char *valuestring) +CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) { - size_t length = 0; char *copy = NULL; - /* if object->valuestring is NULL, it should not set valuestring */ - if (object->valuestring == NULL) + /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ + if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) { return NULL; } - length = strlen(valuestring) + sizeof(""); - copy = (char*) cJSON_malloc(length); + if (strlen(valuestring) <= strlen(object->valuestring)) + { + strcpy(object->valuestring, valuestring); + return object->valuestring; + } + copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); if (copy == NULL) { return NULL; } - memcpy(copy, valuestring, length); - if (!(object->type & cJSON_IsReference) && (object->valuestring != NULL)) + if (object->valuestring != NULL) { cJSON_free(object->valuestring); } diff --git a/cJSON.h b/cJSON.h index 1455ece7..52ad8b44 100644 --- a/cJSON.h +++ b/cJSON.h @@ -278,8 +278,8 @@ CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * c /* helper for the cJSON_SetNumberValue macro */ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) -/* Only takes effect when type of object is JSON_Object */ -CJSON_PUBLIC(char*) cJSON_SetValuestringToObject(cJSON *object, const char *valuestring); +/* 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); /* Macro for iterating over an array or object */ #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index ba494f5c..2538e8d5 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -587,24 +587,34 @@ static void cjson_delete_item_from_array_should_not_broken_list_structure(void) static void cjson_set_valuestring_to_object_should_not_leak_memory(void) { cJSON *root = cJSON_Parse("{}"); - cJSON *item1 = cJSON_CreateString("valuestring could be changed safely"); - cJSON *item2 = cJSON_CreateStringReference("reference item should be freed by yourself"); - const char *newValuestring = "new valuestring which much longer than previous"; - char *returnValue = NULL; + const char *stringvalue = "valuestring could be changed safely"; + const char *reference_valuestring = "reference item should be freed by yourself"; + const char *short_valuestring = "shorter valuestring"; + const char *long_valuestring = "new valuestring which much longer than previous should be changed safely"; + cJSON *item1 = cJSON_CreateString(stringvalue); + cJSON *item2 = cJSON_CreateStringReference(reference_valuestring); + char *ptr1 = NULL; + char *return_value = NULL; cJSON_AddItemToObject(root, "one", item1); cJSON_AddItemToObject(root, "two", item2); + ptr1 = item1->valuestring; + return_value = cJSON_SetValuestring(cJSON_GetObjectItem(root, "one"), short_valuestring); + TEST_ASSERT_NOT_NULL(return_value); + TEST_ASSERT_EQUAL_PTR_MESSAGE(ptr1, return_value, "new valuestring shorter than old should not reallocate memory"); + TEST_ASSERT_EQUAL_STRING(short_valuestring, cJSON_GetObjectItem(root, "one")->valuestring); + /* we needn't to free the original valuestring manually */ - returnValue = cJSON_SetValuestringToObject(cJSON_GetObjectItem(root, "one"), newValuestring); - TEST_ASSERT_NOT_NULL(returnValue); - TEST_ASSERT_EQUAL_STRING(newValuestring, cJSON_GetObjectItem(root, "one")->valuestring); - - returnValue = cJSON_SetValuestringToObject(cJSON_GetObjectItem(root, "two"), newValuestring); - TEST_ASSERT_NOT_NULL(returnValue); - TEST_ASSERT_EQUAL_STRING(newValuestring, cJSON_GetObjectItem(root, "two")->valuestring); - /* we must free the memory manually when the item's type is cJSON_IsReference */ - cJSON_free(item2->valuestring); + ptr1 = item1->valuestring; + return_value = cJSON_SetValuestring(cJSON_GetObjectItem(root, "one"), long_valuestring); + TEST_ASSERT_NOT_NULL(return_value); + TEST_ASSERT_NOT_EQUAL_MESSAGE(ptr1, return_value, "new valuestring longer than old should reallocate memory") + TEST_ASSERT_EQUAL_STRING(long_valuestring, cJSON_GetObjectItem(root, "one")->valuestring); + + return_value = cJSON_SetValuestring(cJSON_GetObjectItem(root, "two"), long_valuestring); + TEST_ASSERT_NULL_MESSAGE(return_value, "valuestring of reference object should not be changed"); + TEST_ASSERT_EQUAL_STRING(reference_valuestring, cJSON_GetObjectItem(root, "two")->valuestring); cJSON_Delete(root); } From 54d6b8016e4b8f4e43b2811ddcd23e58c813f44f Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 26 Mar 2020 14:18:52 +0800 Subject: [PATCH 219/307] add return value for cJSON_AddItemTo... --- cJSON.c | 28 ++++++++++++++-------------- cJSON.h | 10 +++++----- tests/misc_tests.c | 21 ++++++++++++++++++++- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/cJSON.c b/cJSON.c index b0e744e4..acb28b12 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1865,7 +1865,7 @@ static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) { cJSON *child = NULL; - if ((item == NULL) || (array == NULL)) + if ((item == NULL) || (array == NULL) || (array == item)) { return false; } @@ -1904,9 +1904,9 @@ static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) } /* Add item to array/object. */ -CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) { - add_item_to_array(array, item); + return add_item_to_array(array, item); } #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) @@ -1930,7 +1930,7 @@ static cJSON_bool add_item_to_object(cJSON * const object, const char * const st char *new_key = NULL; int new_type = cJSON_Invalid; - if ((object == NULL) || (string == NULL) || (item == NULL)) + if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) { return false; } @@ -1962,35 +1962,35 @@ static cJSON_bool add_item_to_object(cJSON * const object, const char * const st return add_item_to_array(object, item); } -CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) { - add_item_to_object(object, string, item, &global_hooks, false); + return add_item_to_object(object, string, item, &global_hooks, false); } /* Add an item to an object with constant string as key */ -CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) { - add_item_to_object(object, string, item, &global_hooks, true); + return add_item_to_object(object, string, item, &global_hooks, true); } -CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) { if (array == NULL) { - return; + return cJSON_False; } - add_item_to_array(array, create_reference(item, &global_hooks)); + return add_item_to_array(array, create_reference(item, &global_hooks)); } -CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) { if ((object == NULL) || (string == NULL)) { - return; + return cJSON_False; } - add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); + return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); } CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) diff --git a/cJSON.h b/cJSON.h index 2c535628..826f3a1a 100644 --- a/cJSON.h +++ b/cJSON.h @@ -221,15 +221,15 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); /* Append item to the specified array/object. */ -CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); -CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before * writing to `item->string` */ -CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ -CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); -CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); /* Remove/Detach items from Arrays/Objects. */ CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 20a5ddd6..161407e2 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -332,13 +332,15 @@ static void cjson_replace_item_in_object_should_preserve_name(void) cJSON root[1] = {{ NULL, NULL, NULL, 0, NULL, 0, 0, NULL }}; cJSON *child = NULL; cJSON *replacement = NULL; + cJSON_bool flag = cJSON_False; child = cJSON_CreateNumber(1); TEST_ASSERT_NOT_NULL(child); replacement = cJSON_CreateNumber(2); TEST_ASSERT_NOT_NULL(replacement); - cJSON_AddItemToObject(root, "child", child); + flag = cJSON_AddItemToObject(root, "child", child); + TEST_ASSERT_TRUE_MESSAGE(flag, "add item to object failed"); cJSON_ReplaceItemInObject(root, "child", replacement); TEST_ASSERT_TRUE(root->child == replacement); @@ -531,6 +533,22 @@ static void cjson_create_array_reference_should_create_an_array_reference(void) cJSON_Delete(number_reference); } +static void cjson_add_item_to_object_or_array_should_not_add_itself(void) +{ + cJSON *object = cJSON_CreateObject(); + cJSON *array = cJSON_CreateArray(); + cJSON_bool flag = cJSON_False; + + flag = cJSON_AddItemToObject(object, "key", object); + TEST_ASSERT_FALSE_MESSAGE(flag, "add an object to itself should fail"); + + flag = cJSON_AddItemToArray(array, array); + TEST_ASSERT_FALSE_MESSAGE(flag, "add an array to itself should fail"); + + cJSON_Delete(object); + cJSON_Delete(array); +} + static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased(void) { cJSON *object = cJSON_CreateObject(); @@ -607,6 +625,7 @@ int CJSON_CDECL 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_or_array_should_not_add_itself); RUN_TEST(cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased); RUN_TEST(cjson_delete_item_from_array_should_not_broken_list_structure); From bd7cbe9776ed4fc0f2ae55a6a7e1e33761918ccf Mon Sep 17 00:00:00 2001 From: Alanscut Date: Wed, 1 Apr 2020 19:19:00 +0800 Subject: [PATCH 220/307] false has been redefined to cJSON_False --- cJSON.c | 4 ++-- tests/misc_tests.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index acb28b12..95cbc8ba 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1977,7 +1977,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item { if (array == NULL) { - return cJSON_False; + return false; } return add_item_to_array(array, create_reference(item, &global_hooks)); @@ -1987,7 +1987,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const cha { if ((object == NULL) || (string == NULL)) { - return cJSON_False; + return false; } return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 161407e2..d8c2a375 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -332,7 +332,7 @@ static void cjson_replace_item_in_object_should_preserve_name(void) cJSON root[1] = {{ NULL, NULL, NULL, 0, NULL, 0, 0, NULL }}; cJSON *child = NULL; cJSON *replacement = NULL; - cJSON_bool flag = cJSON_False; + cJSON_bool flag = false; child = cJSON_CreateNumber(1); TEST_ASSERT_NOT_NULL(child); @@ -537,7 +537,7 @@ static void cjson_add_item_to_object_or_array_should_not_add_itself(void) { cJSON *object = cJSON_CreateObject(); cJSON *array = cJSON_CreateArray(); - cJSON_bool flag = cJSON_False; + cJSON_bool flag = false; flag = cJSON_AddItemToObject(object, "key", object); TEST_ASSERT_FALSE_MESSAGE(flag, "add an object to itself should fail"); From 131966f748580f97a6201d0908dcf1178bc3bb7a Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 2 Apr 2020 09:11:36 +0800 Subject: [PATCH 221/307] add return value for cJSON_ReplaceItemxxx --- cJSON.c | 26 ++++++++++++-------------- cJSON.h | 8 ++++---- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/cJSON.c b/cJSON.c index 95cbc8ba..39b00697 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2171,20 +2171,19 @@ CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const } /* Replace array/object items with new ones. */ -CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) { cJSON *after_inserted = NULL; if (which < 0) { - return; + return false; } after_inserted = get_array_item(array, (size_t)which); if (after_inserted == NULL) { - add_item_to_array(array, newitem); - return; + return add_item_to_array(array, newitem); } newitem->next = after_inserted; @@ -2198,6 +2197,7 @@ CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newit { newitem->prev->next = newitem; } + return true; } CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) @@ -2241,14 +2241,14 @@ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON return true; } -CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) { if (which < 0) { - return; + return false; } - cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); + return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); } static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) @@ -2266,19 +2266,17 @@ static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSO replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); replacement->type &= ~cJSON_StringIsConst; - cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); - - return true; + return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); } -CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) { - replace_item_in_object(object, string, newitem, false); + return replace_item_in_object(object, string, newitem, false); } -CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) { - replace_item_in_object(object, string, newitem, true); + return replace_item_in_object(object, string, newitem, true); } /* Create basic types: */ diff --git a/cJSON.h b/cJSON.h index 826f3a1a..ae14ced8 100644 --- a/cJSON.h +++ b/cJSON.h @@ -241,11 +241,11 @@ CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); /* Update array items. */ -CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); -CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); -CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); -CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); /* Duplicate a cJSON item */ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); From af56a146fda8167ed8fe04608fe2b7dec7edcb2f Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 2 Apr 2020 11:06:47 +0800 Subject: [PATCH 222/307] update testcase --- tests/misc_tests.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index d8c2a375..714c44db 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -412,19 +412,19 @@ static void cjson_functions_should_not_crash_with_null_pointers(void) cJSON_DeleteItemFromObject(item, NULL); cJSON_DeleteItemFromObjectCaseSensitive(NULL, "item"); cJSON_DeleteItemFromObjectCaseSensitive(item, NULL); - cJSON_InsertItemInArray(NULL, 0, item); - cJSON_InsertItemInArray(item, 0, NULL); + TEST_ASSERT_FALSE(cJSON_InsertItemInArray(NULL, 0, item)); + TEST_ASSERT_FALSE(cJSON_InsertItemInArray(item, 0, NULL)); TEST_ASSERT_FALSE(cJSON_ReplaceItemViaPointer(NULL, item, item)); TEST_ASSERT_FALSE(cJSON_ReplaceItemViaPointer(item, NULL, item)); TEST_ASSERT_FALSE(cJSON_ReplaceItemViaPointer(item, item, NULL)); - cJSON_ReplaceItemInArray(item, 0, NULL); - cJSON_ReplaceItemInArray(NULL, 0, item); - cJSON_ReplaceItemInObject(NULL, "item", item); - cJSON_ReplaceItemInObject(item, NULL, item); - cJSON_ReplaceItemInObject(item, "item", NULL); - cJSON_ReplaceItemInObjectCaseSensitive(NULL, "item", item); - cJSON_ReplaceItemInObjectCaseSensitive(item, NULL, item); - cJSON_ReplaceItemInObjectCaseSensitive(item, "item", NULL); + TEST_ASSERT_FALSE(cJSON_ReplaceItemInArray(item, 0, NULL)); + TEST_ASSERT_FALSE(cJSON_ReplaceItemInArray(NULL, 0, item)); + TEST_ASSERT_FALSE(cJSON_ReplaceItemInObject(NULL, "item", item)); + TEST_ASSERT_FALSE(cJSON_ReplaceItemInObject(item, NULL, item)); + TEST_ASSERT_FALSE(cJSON_ReplaceItemInObject(item, "item", NULL)); + TEST_ASSERT_FALSE(cJSON_ReplaceItemInObjectCaseSensitive(NULL, "item", item)); + TEST_ASSERT_FALSE(cJSON_ReplaceItemInObjectCaseSensitive(item, NULL, item)); + TEST_ASSERT_FALSE(cJSON_ReplaceItemInObjectCaseSensitive(item, "item", NULL)); TEST_ASSERT_NULL(cJSON_Duplicate(NULL, true)); TEST_ASSERT_FALSE(cJSON_Compare(item, NULL, false)); TEST_ASSERT_FALSE(cJSON_Compare(NULL, item, false)); From 8943c733455f12c82c8c82bd9f1c848ae8e91b09 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 2 Apr 2020 16:02:24 +0800 Subject: [PATCH 223/307] comparing double value with DBL_EPSILON --- Makefile | 2 +- cJSON.c | 14 ++++++++++++-- cJSON.h | 5 ----- cJSON_Utils.c | 5 ++++- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 08fcc22e..0e58d5ce 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ else endif PIC_FLAGS = -fPIC -R_CFLAGS = $(PIC_FLAGS) -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 -Wcast-qual -Wc++-compat -Wundef -Wswitch-default -Wconversion -Wfloat-equal $(CFLAGS) +R_CFLAGS = $(PIC_FLAGS) -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 -Wcast-qual -Wc++-compat -Wundef -Wswitch-default -Wconversion $(CFLAGS) uname := $(shell sh -c 'uname -s 2>/dev/null || echo false') diff --git a/cJSON.c b/cJSON.c index b0e744e4..9fc4ffbf 100644 --- a/cJSON.c +++ b/cJSON.c @@ -43,6 +43,7 @@ #include #include #include +#include #ifdef ENABLE_LOCALES #include @@ -68,6 +69,14 @@ #endif #define false ((cJSON_bool)0) +/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ +#ifndef isinf +#define isinf(d) (isnan((d - d)) && !isnan(d)) +#endif +#ifndef isnan +#define isnan(d) (d != d) +#endif + typedef struct { const unsigned char *json; size_t position; @@ -483,7 +492,8 @@ static void update_offset(printbuffer * const buffer) /* securely comparison of floating-point variables */ static cJSON_bool compare_double(double a, double b) { - return (fabs(a - b) <= CJSON_DOUBLE_PRECISION); + double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); + return (fabs(a - b) <= maxVal * DBL_EPSILON); } /* Render the number nicely from the given item into a string. */ @@ -503,7 +513,7 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out } /* This checks for NaN and Infinity */ - if ((d * 0) != 0) + if (isnan(d) || isinf(d)) { length = sprintf((char*)number_buffer, "null"); } diff --git a/cJSON.h b/cJSON.h index 2c535628..753b1ad4 100644 --- a/cJSON.h +++ b/cJSON.h @@ -137,11 +137,6 @@ typedef int cJSON_bool; #define CJSON_NESTING_LIMIT 1000 #endif -/* Precision of double variables comparison */ -#ifndef CJSON_DOUBLE_PRECISION -#define CJSON_DOUBLE_PRECISION .0000000000000001 -#endif - /* returns the version of cJSON as a string */ CJSON_PUBLIC(const char*) cJSON_Version(void); diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 3a535b1d..c750f7fc 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -40,6 +40,8 @@ #include #include #include +#include +#include #if defined(_MSC_VER) #pragma warning (pop) @@ -109,7 +111,8 @@ static int compare_strings(const unsigned char *string1, const unsigned char *st /* securely comparison of floating-point variables */ static cJSON_bool compare_double(double a, double b) { - return (fabs(a - b) <= CJSON_DOUBLE_PRECISION); + double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); + return (fabs(a - b) <= maxVal * DBL_EPSILON); } From 4e114c1f3132e1a4db46ab8e8c6aa33ecde3def8 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 2 Apr 2020 16:24:10 +0800 Subject: [PATCH 224/307] update testcase, fixes #433 --- tests/compare_tests.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/compare_tests.c b/tests/compare_tests.c index 307d0e82..797c7740 100644 --- a/tests/compare_tests.c +++ b/tests/compare_tests.c @@ -64,6 +64,9 @@ static void cjson_compare_should_compare_numbers(void) TEST_ASSERT_TRUE(compare_from_string("1", "1", false)); TEST_ASSERT_TRUE(compare_from_string("0.0001", "0.0001", true)); TEST_ASSERT_TRUE(compare_from_string("0.0001", "0.0001", false)); + TEST_ASSERT_TRUE(compare_from_string("1E100", "10E99", false)); + + TEST_ASSERT_FALSE(compare_from_string("0.5E-100", "0.5E-101", false)); TEST_ASSERT_FALSE(compare_from_string("1", "2", true)); TEST_ASSERT_FALSE(compare_from_string("1", "2", false)); From 983bb2b4d67124688d2116924f0b58c1b80acf88 Mon Sep 17 00:00:00 2001 From: caglarivriz Date: Thu, 2 Apr 2020 11:59:19 +0300 Subject: [PATCH 225/307] Added cJSON_ParseWithLength (#358) Co-authored-by: Caglar Ivriz --- README.md | 8 ++++++ cJSON.c | 33 +++++++++++++++++++++--- cJSON.h | 2 ++ tests/parse_examples.c | 57 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 55aba581..ba544725 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,12 @@ Given some JSON in a zero terminated string, you can parse it with `cJSON_Parse` cJSON *json = cJSON_Parse(string); ``` +Given some JSON in a string (whether zero terminated or not), you can parse it with `cJSON_ParseWithLength`. + +```c +cJSON *json = cJSON_ParseWithLength(string, buffer_length); +``` + It will parse the JSON and allocate a tree of `cJSON` items that represents it. Once it returns, you are fully responsible for deallocating it after use with `cJSON_Delete`. The allocator used by `cJSON_Parse` is `malloc` and `free` by default but can be changed (globally) with `cJSON_InitHooks`. @@ -277,6 +283,8 @@ By default, characters in the input string that follow the parsed JSON will not If you want more options, use `cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)`. `return_parse_end` returns a pointer to the end of the JSON in the input string or the position that an error occurs at (thereby replacing `cJSON_GetErrorPtr` in a thread safe way). `require_null_terminated`, if set to `1` will make it an error if the input string contains data after the JSON. +If you want more options giving buffer length, use `cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)`. + ### Printing JSON Given a tree of `cJSON` items, you can print them as a string using `cJSON_Print`. diff --git a/cJSON.c b/cJSON.c index b0e744e4..82d4debe 100644 --- a/cJSON.c +++ b/cJSON.c @@ -983,6 +983,11 @@ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) return NULL; } + if (cannot_access_at_index(buffer, 0)) + { + return buffer; + } + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) { buffer->offset++; @@ -1012,8 +1017,23 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) return buffer; } -/* Parse an object - create a new root, and populate. */ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + size_t buffer_length; + + if (NULL == value) + { + return NULL; + } + + /* Adding null character size due to require_null_terminated. */ + buffer_length = strlen(value) + sizeof(""); + + return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) { parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; cJSON *item = NULL; @@ -1022,13 +1042,13 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return global_error.json = NULL; global_error.position = 0; - if (value == NULL) + if (value == NULL || 0 == buffer_length) { goto fail; } buffer.content = (const unsigned char*)value; - buffer.length = strlen((const char*)value) + sizeof(""); + buffer.length = buffer_length; buffer.offset = 0; buffer.hooks = global_hooks; @@ -1098,7 +1118,12 @@ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) return cJSON_ParseWithOpts(value, 0, 0); } -#define cjson_min(a, b) ((a < b) ? a : b) +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) +{ + return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); +} + +#define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) { diff --git a/cJSON.h b/cJSON.h index 2c535628..e98ab64d 100644 --- a/cJSON.h +++ b/cJSON.h @@ -151,9 +151,11 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); +CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); /* Render a cJSON entity to text for transfer/storage. */ CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); diff --git a/tests/parse_examples.c b/tests/parse_examples.c index 3aab77fe..95a09590 100644 --- a/tests/parse_examples.c +++ b/tests/parse_examples.c @@ -195,6 +195,61 @@ static void test12_should_not_be_parsed(void) } } +static void test13_should_be_parsed_without_null_termination(void) +{ + cJSON *tree = NULL; + const char test_13[] = "{" \ + "\"Image\":{" \ + "\"Width\":800," \ + "\"Height\":600," \ + "\"Title\":\"Viewfrom15thFloor\"," \ + "\"Thumbnail\":{" \ + "\"Url\":\"http:/*www.example.com/image/481989943\"," \ + "\"Height\":125," \ + "\"Width\":\"100\"" \ + "}," \ + "\"IDs\":[116,943,234,38793]" \ + "}" \ + "}"; + + char test_13_wo_null[sizeof(test_13) - 1]; + memcpy(test_13_wo_null, test_13, sizeof(test_13) - 1); + + tree = cJSON_ParseWithLength(test_13_wo_null, sizeof(test_13) - 1); + TEST_ASSERT_NOT_NULL_MESSAGE(tree, "Failed to parse valid json."); + + if (tree != NULL) + { + cJSON_Delete(tree); + } +} + +static void test14_should_not_be_parsed(void) +{ + cJSON *tree = NULL; + const char test_14[] = "{" \ + "\"Image\":{" \ + "\"Width\":800," \ + "\"Height\":600," \ + "\"Title\":\"Viewfrom15thFloor\"," \ + "\"Thumbnail\":{" \ + "\"Url\":\"http:/*www.example.com/image/481989943\"," \ + "\"Height\":125," \ + "\"Width\":\"100\"" \ + "}," \ + "\"IDs\":[116,943,234,38793]" \ + "}" \ + "}"; + + tree = cJSON_ParseWithLength(test_14, sizeof(test_14) - 2); + TEST_ASSERT_NULL_MESSAGE(tree, "Should not continue after buffer_length is reached."); + + if (tree != NULL) + { + cJSON_Delete(tree); + } +} + int CJSON_CDECL main(void) { UNITY_BEGIN(); @@ -210,5 +265,7 @@ int CJSON_CDECL main(void) RUN_TEST(file_test10_should_be_parsed_and_printed); RUN_TEST(file_test11_should_be_parsed_and_printed); RUN_TEST(test12_should_not_be_parsed); + RUN_TEST(test13_should_be_parsed_without_null_termination); + RUN_TEST(test14_should_not_be_parsed); return UNITY_END(); } From 97cf1d84e4688d0f5c96e67848770f9a58632e03 Mon Sep 17 00:00:00 2001 From: Sang-Heon Jeon Date: Thu, 2 Apr 2020 18:06:56 +0900 Subject: [PATCH 226/307] Add getNumberValue function * Add GetNumberValue function and testcase Co-authored-by: Alan Wang --- cJSON.c | 16 ++++++++++++++-- cJSON.h | 5 +++-- tests/misc_tests.c | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index 82d4debe..426b6125 100644 --- a/cJSON.c +++ b/cJSON.c @@ -79,14 +79,26 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) return (const char*) (global_error.json + global_error.position); } -CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) { - if (!cJSON_IsString(item)) { +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) +{ + if (!cJSON_IsString(item)) + { return NULL; } return item->valuestring; } +CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item) +{ + if (!cJSON_IsNumber(item)) + { + return 0.0/0.0; + } + + return item->valuedouble; +} + /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 12) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. diff --git a/cJSON.h b/cJSON.h index e98ab64d..a6a13a5c 100644 --- a/cJSON.h +++ b/cJSON.h @@ -180,8 +180,9 @@ CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *st /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); -/* Check if the item is a string and return its valuestring */ -CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); +/* Check item type and return its value */ +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); +CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item); /* These functions check the type of an item */ CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 20a5ddd6..534a7c6c 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -486,6 +486,19 @@ static void cjson_get_string_value_should_get_a_string(void) cJSON_Delete(string); } +static void cjson_get_number_value_should_get_a_number(void) +{ + cJSON *string = cJSON_CreateString("test"); + cJSON *number = cJSON_CreateNumber(1); + + TEST_ASSERT_EQUAL_DOUBLE(cJSON_GetNumberValue(number), number->valuedouble); + TEST_ASSERT_DOUBLE_IS_NAN(cJSON_GetNumberValue(string)); + TEST_ASSERT_DOUBLE_IS_NAN(cJSON_GetNumberValue(NULL)); + + cJSON_Delete(number); + cJSON_Delete(string); +} + static void cjson_create_string_reference_should_create_a_string_reference(void) { const char *string = "I am a string!"; @@ -604,6 +617,7 @@ int CJSON_CDECL main(void) RUN_TEST(skip_utf8_bom_should_skip_bom); RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); RUN_TEST(cjson_get_string_value_should_get_a_string); + RUN_TEST(cjson_get_number_value_should_get_a_number); 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); From 5d55c6c2ee77805f4c8943ed419fb97fb60d748d Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 2 Apr 2020 23:32:30 +0800 Subject: [PATCH 227/307] fix error C2124 in visual studio --- cJSON.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 5bde9066..5a666db2 100644 --- a/cJSON.c +++ b/cJSON.c @@ -77,6 +77,10 @@ #define isnan(d) (d != d) #endif +#ifndef NAN +#define NAN 0.0/0.0 +#endif + typedef struct { const unsigned char *json; size_t position; @@ -102,7 +106,7 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item) { if (!cJSON_IsNumber(item)) { - return 0.0/0.0; + return NAN; } return item->valuedouble; From ff0dabc72e261d34eb7d4a84349dd98286f0910e Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 2 Apr 2020 23:34:28 +0800 Subject: [PATCH 228/307] Update version to 1.7.13 --- CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 34ad39f2..913c1524 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 12) +set(PROJECT_VERSION_PATCH 13) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 0e58d5ce..4e727b73 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.12 +LIBVERSION = 1.7.13 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 5a666db2..a5d39878 100644 --- a/cJSON.c +++ b/cJSON.c @@ -113,7 +113,7 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 12) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 13) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 0f832d25..0c6c8e07 100644 --- a/cJSON.h +++ b/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 12 +#define CJSON_VERSION_PATCH 13 #include From 39853e5148dad8dc5d32ea2b00943cf4a0c6f120 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 2 Apr 2020 23:35:50 +0800 Subject: [PATCH 229/307] Update changelog --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ec6cb40..ec63a513 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +1.7.13 (Apr 2, 2020) +====== +Features: +--------- +* add new API of cJSON_ParseWithLength without breaking changes. Thanks @caglarivriz, see [#358](https://github.com/DaveGamble/cJSON/pull/358) +* add new API of cJSON_GetNumberValue. Thanks @Intuition, see[#385](https://github.com/DaveGamble/cJSON/pull/385) +* add uninstall target function for CMake. See [#402](https://github.com/DaveGamble/cJSON/pull/402) +* Improve performance of adding item to array. Thanks @xiaomianhehe, see [#430](https://github.com/DaveGamble/cJSON/pull/430), [#448](https://github.com/DaveGamble/cJSON/pull/448) +* add new API of cJSON_SetValuestring, for changing the valuestring safely. See [#451](https://github.com/DaveGamble/cJSON/pull/451) +* add return value for cJSON_AddItemTo... and cJSON_ReplaceItem... (check if the operation successful). See [#453](https://github.com/DaveGamble/cJSON/pull/453) + +Fixes: +------ +* Fix clang -Wfloat-equal warning. Thanks @paulmalovanyi, see [#368](https://github.com/DaveGamble/cJSON/pull/368) +* Fix make failed in mac os. See [#405](https://github.com/DaveGamble/cJSON/pull/405) +* Fix memory leak in cJSONUtils_FindPointerFromObjectTo. Thanks @andywolk for reporting, see [#414](https://github.com/DaveGamble/cJSON/issues/414) +* Fix bug in encode_string_as_pointer. Thanks @AIChangJiang for reporting, see [#439](https://github.com/DaveGamble/cJSON/issues/439) + 1.7.12 (May 17, 2019) ====== Fixes: From 3999b12848214a201bf56ef416b9dac1ec63f811 Mon Sep 17 00:00:00 2001 From: miaoerduo Date: Fri, 3 Apr 2020 11:52:54 +0800 Subject: [PATCH 230/307] feat: set list head's prev in parse_array and parse_object --- cJSON.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cJSON.c b/cJSON.c index a5d39878..500fcf57 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1509,6 +1509,10 @@ static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buf success: input_buffer->depth--; + if (head != NULL) { + head->prev = current_item; + } + item->type = cJSON_Array; item->child = head; @@ -1681,6 +1685,10 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu success: input_buffer->depth--; + if (head != NULL) { + head->prev = current_item; + } + item->type = cJSON_Object; item->child = head; From a65abf2f4f1842765761a616e93c14ae25a284fd Mon Sep 17 00:00:00 2001 From: miaoerduo Date: Fri, 3 Apr 2020 14:07:22 +0800 Subject: [PATCH 231/307] fix: error list head's prev when detach the last item --- cJSON.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cJSON.c b/cJSON.c index 500fcf57..cc1c0166 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2210,6 +2210,12 @@ CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const it /* first element */ parent->child = item->next; } + else if (item->next == NULL) + { + /* last element */ + parent->child->prev = item->prev; + } + /* make sure the detached item doesn't point anywhere anymore */ item->prev = NULL; item->next = NULL; From cb4661cd91fc6d6f9e81b627967735f7072f901c Mon Sep 17 00:00:00 2001 From: miaoerduo Date: Fri, 3 Apr 2020 14:47:49 +0800 Subject: [PATCH 232/307] fix: errors in replacing the first item when array_size is 1, and replacing the last item --- cJSON.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cJSON.c b/cJSON.c index cc1c0166..23270c48 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2313,6 +2313,10 @@ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON } if (parent->child == item) { + if (parent->child->prev == parent->child) + { + replacement->prev = replacement; + } parent->child = replacement; } else @@ -2324,6 +2328,10 @@ CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON { replacement->prev->next = replacement; } + if (replacement->next == NULL) + { + parent->child->prev = replacement; + } } item->next = NULL; From 3442b366720d1046c827b4df4b26ccd0ecb66b2c Mon Sep 17 00:00:00 2001 From: Romain Lesteven Date: Fri, 17 Apr 2020 12:01:39 +0200 Subject: [PATCH 233/307] Fix make.sh install unwanted config files --- CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 913c1524..0a73a2c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,10 +223,12 @@ configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/library_config/cJSONConfigVersion.cmake.in" ${PROJECT_BINARY_DIR}/cJSONConfigVersion.cmake @ONLY) -# Install package config files -install(FILES ${PROJECT_BINARY_DIR}/cJSONConfig.cmake - ${PROJECT_BINARY_DIR}/cJSONConfigVersion.cmake - DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON") +if(ENABLE_TARGET_EXPORT) + # Install package config files + install(FILES ${PROJECT_BINARY_DIR}/cJSONConfig.cmake + ${PROJECT_BINARY_DIR}/cJSONConfigVersion.cmake + DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON") +endif() option(ENABLE_CJSON_TEST "Enable building cJSON test" ON) if(ENABLE_CJSON_TEST) From 7103844037668db882ae183845735ec08249fd1a Mon Sep 17 00:00:00 2001 From: Moorthy <36617743+moorthy-bs@users.noreply.github.com> Date: Thu, 30 Apr 2020 16:13:44 +0530 Subject: [PATCH 234/307] pkgconfig: cjson include dir added fixed #468 --- library_config/libcjson.pc.in | 2 +- library_config/libcjson_utils.pc.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library_config/libcjson.pc.in b/library_config/libcjson.pc.in index 157a4653..de48fe05 100644 --- a/library_config/libcjson.pc.in +++ b/library_config/libcjson.pc.in @@ -7,4 +7,4 @@ Description: Ultralightweight JSON parser in ANSI C URL: https://github.com/DaveGamble/cJSON Libs: -L${libdir} -lcjson Libs.private: -lm -Cflags: -I${includedir} +Cflags: -I${includedir} -I${includedir}/cjson diff --git a/library_config/libcjson_utils.pc.in b/library_config/libcjson_utils.pc.in index 830259fa..df2b4e5b 100644 --- a/library_config/libcjson_utils.pc.in +++ b/library_config/libcjson_utils.pc.in @@ -6,5 +6,5 @@ Version: @PROJECT_VERSION@ Description: An implementation of JSON Pointer, Patch and Merge Patch based on cJSON. URL: https://github.com/DaveGamble/cJSON Libs: -L${libdir} -lcjson_utils -Cflags: -I${includedir} +Cflags: -I${includedir} -I${includedir}/cjson Requires: libcjson From 1fc755ac0964cd56d9a2564967dc4747be223f23 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Wed, 6 May 2020 17:18:42 +0800 Subject: [PATCH 235/307] array's item should be in the list --- tests/parse_array.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/parse_array.c b/tests/parse_array.c index dfaae29b..d013f224 100644 --- a/tests/parse_array.c +++ b/tests/parse_array.c @@ -90,7 +90,8 @@ static void parse_array_should_parse_arrays_with_one_element(void) assert_parse_array("[[]]"); assert_has_child(item); - assert_is_array(item->child); + TEST_ASSERT_NOT_NULL(item->child); + assert_has_type(item->child, cJSON_Array); assert_has_no_child(item->child); reset(item); From b95a4c56b05fb3200780c1cacc3b1659a2832f8e Mon Sep 17 00:00:00 2001 From: Alanscut Date: Mon, 22 Jun 2020 11:23:24 +0800 Subject: [PATCH 236/307] fix #376 --- cJSON.c | 4 ++-- cJSON.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index 23270c48..3cdc8fa5 100644 --- a/cJSON.c +++ b/cJSON.c @@ -92,7 +92,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) return (const char*) (global_error.json + global_error.position); } -CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) { if (!cJSON_IsString(item)) { @@ -102,7 +102,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) return item->valuestring; } -CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item) +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) { if (!cJSON_IsNumber(item)) { diff --git a/cJSON.h b/cJSON.h index 0c6c8e07..b5ceb290 100644 --- a/cJSON.h +++ b/cJSON.h @@ -176,8 +176,8 @@ CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *st CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); /* Check item type and return its value */ -CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); -CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item); +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); /* These functions check the type of an item */ CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); From 4578d3a9e143224e75ab74b14dd73865cbf0338b Mon Sep 17 00:00:00 2001 From: Kevin Sapper Date: Tue, 23 Jun 2020 09:16:26 +0200 Subject: [PATCH 237/307] Problem: WError error on macosx because NAN is a float Solution: Add explicit cast from NAN to double --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 3cdc8fa5..7518389b 100644 --- a/cJSON.c +++ b/cJSON.c @@ -106,7 +106,7 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) { if (!cJSON_IsNumber(item)) { - return NAN; + return (double) NAN; } return item->valuedouble; From 1ef4deec0664b2500212da805c017ef08c96b500 Mon Sep 17 00:00:00 2001 From: h00283522 Date: Fri, 26 Jun 2020 10:37:00 +0800 Subject: [PATCH 238/307] Remove unnecessary files in release tarball Prior to this patch, we would find '.gitignore', '.travisCI.yml' in the release tarball. This patch adds a few entries in .gitattributes to specify files that should never end up in a distribution tarball. Signed-off-by: Hu Keping --- .gitattributes | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 6e5ee10e..7491fcc7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,8 @@ * text=auto -/tests/inputs/* text eol=lf \ No newline at end of file +/tests/inputs/* text eol=lf + +.gitattributes export-ignore +.gitignore export-ignore +.github export-ignore +.editorconfig export-ignore +.travis.yml export-ignore From 857c037ccce67ca58da196f1dd46d3d4a21f6474 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 27 Aug 2020 20:26:04 +0800 Subject: [PATCH 239/307] add github actions CI --- .github/workflows/CI.yml | 102 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 .github/workflows/CI.yml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 00000000..dc9d17c6 --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,102 @@ +name: CI + +on: + push: + branches: [ master ] + paths-ignore: + - '**.md' + - 'LICENSE' + pull_request: + types: [opened, synchronize] + paths-ignore: + - '**.md' + - 'LICENSE' + +jobs: + linux: + runs-on: ubuntu-latest + if: "!contains(github.event.head_commit.message, 'ci skip')" + strategy: + fail-fast: false + matrix: + mem_check: + - ENABLE_VALGRIND + - ENABLE_SANITIZERS + - NONE_MEM_CHECK + compiler: + - GCC + - CLANG + steps: + - uses: actions/checkout@v2 + - name: install build dependencies + run: | + sudo apt-get update + sudo apt-get install clang-8 valgrind + - name: build and test + shell: bash + run: | + if [ "${{ matrix.mem_check }}" == "ENABLE_VALGRIND" ]; then + EVENT_CMAKE_OPTIONS="-DENABLE_CJSON_UTILS=ON -DENABLE_VALGRIND=ON -DENABLE_SAFE_STACK=ON -DENABLE_SANITIZERS=OFF" + elif [ "${{ matrix.mem_check }}" == "ENABLE_SANITIZERS" ]; then + EVENT_CMAKE_OPTIONS="-DENABLE_CJSON_UTILS=ON -DENABLE_VALGRIND=OFF -DENABLE_SAFE_STACK=OFF -DENABLE_SANITIZERS=ON" + else + EVENT_CMAKE_OPTIONS="-DENABLE_CJSON_UTILS=ON -DENABLE_VALGRIND=OFF -DENABLE_SAFE_STACK=OFF -DENABLE_SANITIZERS=OFF" + fi + if [ "${{ matrix.compiler }}" == "GCC" ]; then + export CC=gcc + else + export CC=clang + fi + #run build and test + JOBS=20 + export CTEST_PARALLEL_LEVEL=$JOBS + export CTEST_OUTPUT_ON_FAILURE=1 + mkdir -p build + cd build + echo [cmake]: cmake .. $EVENT_CMAKE_OPTIONS + cmake .. $EVENT_CMAKE_OPTIONS || (rm -rf * && cmake .. $EVENT_CMAKE_OPTIONS) + cmake --build . + make + make test + + macos: + runs-on: macos-latest + if: "!contains(github.event.head_commit.message, 'ci skip')" + strategy: + fail-fast: false + matrix: + mem_check: + - ENABLE_VALGRIND + - ENABLE_SANITIZERS + - NONE_MEM_CHECK + compiler: + - GCC + - CLANG + steps: + - uses: actions/checkout@v2 + - name: build and test + shell: bash + run: | + if [ "${{ matrix.mem_check }}" == "ENABLE_VALGRIND" ]; then + EVENT_CMAKE_OPTIONS="-DENABLE_CJSON_UTILS=ON -DENABLE_VALGRIND=ON -DENABLE_SAFE_STACK=ON -DENABLE_SANITIZERS=OFF" + elif [ "${{ matrix.mem_check }}" == "ENABLE_SANITIZERS" ]; then + EVENT_CMAKE_OPTIONS="-DENABLE_CJSON_UTILS=ON -DENABLE_VALGRIND=OFF -DENABLE_SAFE_STACK=OFF -DENABLE_SANITIZERS=ON" + else + EVENT_CMAKE_OPTIONS="-DENABLE_CJSON_UTILS=ON -DENABLE_VALGRIND=OFF -DENABLE_SAFE_STACK=OFF -DENABLE_SANITIZERS=OFF" + fi + if [ "${{ matrix.compiler }}" == "GCC" ]; then + export CC=gcc + else + export CC=clang + fi + #run build and test + JOBS=20 + export CTEST_PARALLEL_LEVEL=$JOBS + export CTEST_OUTPUT_ON_FAILURE=1 + mkdir -p build + cd build + echo [cmake]: cmake .. $EVENT_CMAKE_OPTIONS + cmake .. $EVENT_CMAKE_OPTIONS || (rm -rf * && cmake .. $EVENT_CMAKE_OPTIONS) + cmake --build . + make + make test From 23f027139e5f0da860b41e6b8eb3045ba08335e8 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 27 Aug 2020 20:46:00 +0800 Subject: [PATCH 240/307] remove float-divide-by-zero for supporting NAN --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a73a2c2..4c369404 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,7 +68,6 @@ if (ENABLE_SANITIZERS) -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined - -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fsanitize-address-use-after-scope -fsanitize=integer From c8ca78a3cc2045f3714f04dab7152a67215bca80 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Wed, 2 Sep 2020 20:23:52 +0800 Subject: [PATCH 241/307] optimize the way to find tail node --- cJSON.c | 17 ++++++++--------- cJSON_Utils.c | 8 ++++++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/cJSON.c b/cJSON.c index 7518389b..0acf487d 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1975,15 +1975,6 @@ static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) suffix_object(child->prev, item); array->child->prev = item; } - else - { - while (child->next) - { - child = child->next; - } - suffix_object(child, item); - array->child->prev = item; - } } return true; @@ -2571,6 +2562,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) } p = n; } + a->child->prev = n; return a; } @@ -2607,6 +2599,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) } p = n; } + a->child->prev = n; return a; } @@ -2643,6 +2636,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) } p = n; } + a->child->prev = n; return a; } @@ -2679,6 +2673,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int co } p = n; } + a->child->prev = n; return a; } @@ -2751,6 +2746,10 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) } child = child->next; } + if (newitem && newitem->child) + { + newitem->child->prev = newchild; + } return newitem; diff --git a/cJSON_Utils.c b/cJSON_Utils.c index c750f7fc..f4ad32a5 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -403,7 +403,7 @@ static cJSON *detach_item_from_array(cJSON *array, size_t which) /* item doesn't exist */ return NULL; } - if (c->prev) + if (c != array->child) { /* not the first element */ c->prev->next = c->next; @@ -412,10 +412,14 @@ static cJSON *detach_item_from_array(cJSON *array, size_t which) { c->next->prev = c->prev; } - if (c==array->child) + if (c == array->child) { array->child = c->next; } + else if (c->next == NULL) + { + array->child->prev = c->prev; + } /* make sure the detached item doesn't point anywhere anymore */ c->prev = c->next = NULL; From 8e357f825b12a91931a518949e24b77685ee609b Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 3 Sep 2020 17:07:49 +0800 Subject: [PATCH 242/307] Update version to 1.7.14 --- CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c369404..e8c96342 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 13) +set(PROJECT_VERSION_PATCH 14) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index 4e727b73..b1432305 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.13 +LIBVERSION = 1.7.14 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 0acf487d..4c6a308e 100644 --- a/cJSON.c +++ b/cJSON.c @@ -113,7 +113,7 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 13) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index b5ceb290..e97e5f4c 100644 --- a/cJSON.h +++ b/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 13 +#define CJSON_VERSION_PATCH 14 #include From 8e84db4c4e631c5578a1d2365bbcc9d814ab8a51 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 3 Sep 2020 17:11:02 +0800 Subject: [PATCH 243/307] Update changelog and contributors --- CHANGELOG.md | 8 ++++++++ CONTRIBUTORS.md | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec63a513..ff0f5b2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +1.7.14 (Sep 3, 2020) +====== +Fixes: +------ +* optimize the way to find tail node, see [#503](https://github.com/DaveGamble/cJSON/pull/503) +* Fix WError error on macosx because NAN is a float. Thanks @sappo, see [#484](https://github.com/DaveGamble/cJSON/pull/484) +* Fix some bugs in detach and replace. Thanks @miaoerduo, see [#456](https://github.com/DaveGamble/cJSON/pull/456) + 1.7.13 (Apr 2, 2020) ====== Features: diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 0552025d..f113ab22 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -29,6 +29,7 @@ Contributors: * [Fabrice Fontaine](https://github.com/ffontaine) * Ian Mobley * Irwan Djadjadi +* [HuKeping](https://github.com/HuKeping) * [IvanVoid](https://github.com/npi3pak) * [Jakub Wilk](https://github.com/jwilk) * [Jiri Zouhar](https://github.com/loigu) @@ -36,12 +37,15 @@ Contributors: * [Julian Ste](https://github.com/julian-st) * [Julián Vásquez](https://github.com/juvasquezg) * [Kevin Branigan](https://github.com/kbranigan) +* [Kevin Sapper](https://github.com/sappo) * [Kyle Chisholm](https://github.com/ChisholmKyle) * [Linus Wallgren](https://github.com/ecksun) * [Mateusz Szafoni](https://github.com/raiden00pl) * Mike Pontillo +* [miaoerduo](https://github.com/miaoerduo) * [Mike Jerris](https://github.com/mjerris) * [Mike Robinson](https://github.com/mhrobinson) +* [Moorthy](https://github.com/moorthy-bs) * [myd7349](https://github.com/myd7349) * [NancyLi1013](https://github.com/NancyLi1013) * Paulo Antonio Alvarez From 9931900768d51e331e8433c4ffdc2de0c637369d Mon Sep 17 00:00:00 2001 From: Use Date: Thu, 15 Oct 2020 11:52:06 +0900 Subject: [PATCH 244/307] fix: windows build failure about defining nan --- cJSON.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cJSON.c b/cJSON.c index 4c6a308e..6bc102bf 100644 --- a/cJSON.c +++ b/cJSON.c @@ -78,8 +78,12 @@ #endif #ifndef NAN +#ifdef _WIN32 +#define NAN sqrt(-1.0) +#else #define NAN 0.0/0.0 #endif +#endif typedef struct { const unsigned char *json; From 9bf4960cd525428ddbfb9b13f39c4269083b18d7 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Fri, 16 Oct 2020 17:06:29 +0800 Subject: [PATCH 245/307] fix a possible dereference of null pointer --- cJSON_Utils.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index f4ad32a5..8e70e003 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1406,6 +1406,10 @@ static cJSON *generate_merge_patch(cJSON * const from, cJSON * const to, const c from_child = from->child; to_child = to->child; patch = cJSON_CreateObject(); + if (patch == NULL) + { + return NULL; + } while (from_child || to_child) { int diff; From 2f6fc7f0f28b4dab68a3d7fcf447beabefd04afb Mon Sep 17 00:00:00 2001 From: mongobaba <66656234+mongobaba@users.noreply.github.com> Date: Thu, 12 Nov 2020 11:46:15 +0800 Subject: [PATCH 246/307] fix several null pointer problems on allocation failure (#526) --- cJSON.c | 25 ++++++++++++++++++++---- tests/cjson_add.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index 6bc102bf..c06279d4 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2548,7 +2548,12 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) } a = cJSON_CreateArray(); - for(i = 0; a && (i < (size_t)count); i++) + if (!a) + { + return NULL; + } + + for(i = 0; i < (size_t)count; i++) { n = cJSON_CreateNumber(numbers[i]); if (!n) @@ -2584,8 +2589,12 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) } a = cJSON_CreateArray(); + if (!a) + { + return NULL; + } - for(i = 0; a && (i < (size_t)count); i++) + for(i = 0; i < (size_t)count; i++) { n = cJSON_CreateNumber((double)numbers[i]); if(!n) @@ -2621,8 +2630,12 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) } a = cJSON_CreateArray(); + if (!a) + { + return NULL; + } - for(i = 0;a && (i < (size_t)count); i++) + for(i = 0; i < (size_t)count; i++) { n = cJSON_CreateNumber(numbers[i]); if(!n) @@ -2658,8 +2671,12 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int co } a = cJSON_CreateArray(); + if (!a) + { + return NULL; + } - for (i = 0; a && (i < (size_t)count); i++) + for (i = 0; i < (size_t)count; i++) { n = cJSON_CreateString(strings[i]); if(!n) diff --git a/tests/cjson_add.c b/tests/cjson_add.c index 00ffc349..b02f1e27 100644 --- a/tests/cjson_add.c +++ b/tests/cjson_add.c @@ -117,6 +117,50 @@ static void cjson_add_true_should_fail_on_allocation_failure(void) cJSON_Delete(root); } +static void cjson_create_int_array_should_fail_on_allocation_failure(void) +{ + int numbers[] = {1, 2, 3}; + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_CreateIntArray(numbers, 3)); + + cJSON_InitHooks(NULL); +} + +static void cjson_create_float_array_should_fail_on_allocation_failure(void) +{ + float numbers[] = {1.0f, 2.0f, 3.0f}; + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_CreateFloatArray(numbers, 3)); + + cJSON_InitHooks(NULL); +} + +static void cjson_create_double_array_should_fail_on_allocation_failure(void) +{ + double numbers[] = {1.0, 2.0, 3.0}; + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_CreateDoubleArray(numbers, 3)); + + cJSON_InitHooks(NULL); +} + +static void cjson_create_string_array_should_fail_on_allocation_failure(void) +{ + const char* strings[] = {"1", "2", "3"}; + + cJSON_InitHooks(&failing_hooks); + + TEST_ASSERT_NULL(cJSON_CreateStringArray(strings, 3)); + + cJSON_InitHooks(NULL); +} + static void cjson_add_false_should_add_false(void) { cJSON *root = cJSON_CreateObject(); @@ -390,6 +434,11 @@ int CJSON_CDECL main(void) RUN_TEST(cjson_add_true_should_fail_with_null_pointers); RUN_TEST(cjson_add_true_should_fail_on_allocation_failure); + RUN_TEST(cjson_create_int_array_should_fail_on_allocation_failure); + RUN_TEST(cjson_create_float_array_should_fail_on_allocation_failure); + RUN_TEST(cjson_create_double_array_should_fail_on_allocation_failure); + RUN_TEST(cjson_create_string_array_should_fail_on_allocation_failure); + RUN_TEST(cjson_add_false_should_add_false); RUN_TEST(cjson_add_false_should_fail_with_null_pointers); RUN_TEST(cjson_add_false_should_fail_on_allocation_failure); From 4100379a04f2f2838ffb00c4ad3d0dd9e49f4147 Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Mon, 16 Nov 2020 11:57:02 +1100 Subject: [PATCH 247/307] docs: fix simple typo, transfering -> transferring (#527) There is a small typo in tests/readme_examples.c. Should read `transferring` rather than `transfering`. --- tests/readme_examples.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/readme_examples.c b/tests/readme_examples.c index 80ea8aa1..09850cd4 100644 --- a/tests/readme_examples.c +++ b/tests/readme_examples.c @@ -69,7 +69,7 @@ static char* create_monitor(void) goto end; } /* after creation was successful, immediately add it to the monitor, - * thereby transfering ownership of the pointer to it */ + * thereby transferring ownership of the pointer to it */ cJSON_AddItemToObject(monitor, "name", name); resolutions = cJSON_CreateArray(); From 7b6645794d67eebb20678d8d30e8e8ba5357184a Mon Sep 17 00:00:00 2001 From: Alan Wang Date: Thu, 17 Dec 2020 15:42:31 +0800 Subject: [PATCH 248/307] Fix null pointer crash, closes #536 (#538) --- cJSON.c | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/cJSON.c b/cJSON.c index c06279d4..0f079ae1 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2548,12 +2548,8 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) } a = cJSON_CreateArray(); - if (!a) - { - return NULL; - } - for(i = 0; i < (size_t)count; i++) + for(i = 0; a && (i < (size_t)count); i++) { n = cJSON_CreateNumber(numbers[i]); if (!n) @@ -2571,7 +2567,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) } p = n; } - a->child->prev = n; + + if (a && a->child) { + a->child->prev = n; + } return a; } @@ -2589,12 +2588,8 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) } a = cJSON_CreateArray(); - if (!a) - { - return NULL; - } - for(i = 0; i < (size_t)count; i++) + for(i = 0; a && (i < (size_t)count); i++) { n = cJSON_CreateNumber((double)numbers[i]); if(!n) @@ -2612,7 +2607,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) } p = n; } - a->child->prev = n; + + if (a && a->child) { + a->child->prev = n; + } return a; } @@ -2630,12 +2628,8 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) } a = cJSON_CreateArray(); - if (!a) - { - return NULL; - } - for(i = 0; i < (size_t)count; i++) + for(i = 0; a && (i < (size_t)count); i++) { n = cJSON_CreateNumber(numbers[i]); if(!n) @@ -2653,7 +2647,10 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) } p = n; } - a->child->prev = n; + + if (a && a->child) { + a->child->prev = n; + } return a; } @@ -2671,12 +2668,8 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int co } a = cJSON_CreateArray(); - if (!a) - { - return NULL; - } - for (i = 0; i < (size_t)count; i++) + for (i = 0; a && (i < (size_t)count); i++) { n = cJSON_CreateString(strings[i]); if(!n) @@ -2694,8 +2687,11 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int co } p = n; } - a->child->prev = n; + if (a && a->child) { + a->child->prev = n; + } + return a; } From 9226e4ed8c282c2d25669646e8802d00321a57dc Mon Sep 17 00:00:00 2001 From: Jordan IMBERT Date: Thu, 17 Dec 2020 10:07:18 +0100 Subject: [PATCH 249/307] Remove always true condition in cJSON.c (#539) --- cJSON.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index 0f079ae1..030311ce 100644 --- a/cJSON.c +++ b/cJSON.c @@ -511,10 +511,8 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) return NULL; } - if (newbuffer) - { - memcpy(newbuffer, p->buffer, p->offset + 1); - } + + memcpy(newbuffer, p->buffer, p->offset + 1); p->hooks.deallocate(p->buffer); } p->length = newsize; From 6ea4c01e4e6ff579de0ae4a5f44768307cbb9c69 Mon Sep 17 00:00:00 2001 From: Alan Wang Date: Thu, 31 Dec 2020 10:26:39 +0800 Subject: [PATCH 250/307] Fix potential core dumped for strrchr (#546) --- cJSON_Utils.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 8e70e003..c7c64391 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -960,7 +960,9 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_ /* split pointer in parent and child */ parent_pointer = cJSONUtils_strdup((unsigned char*)path->valuestring); - child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/'); + if (parent_pointer) { + child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/'); + } if (child_pointer != NULL) { child_pointer[0] = '\0'; From 324a6ac9a9b285ff7a5a3e5b2071e3624b94f2db Mon Sep 17 00:00:00 2001 From: CoffeeTableEspresso Date: Wed, 30 Dec 2020 21:38:10 -0500 Subject: [PATCH 251/307] Update .gitattributes (#544) --- .gitattributes | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitattributes b/.gitattributes index 7491fcc7..883895fb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,3 +6,6 @@ .github export-ignore .editorconfig export-ignore .travis.yml export-ignore + +# Linguist incorrectly identified the headers as C++, manually override this. +*.h linguist-language=C From 7795249dd42ad4fa9874c57947a699567b896fd1 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Wed, 25 Aug 2021 10:01:12 +0300 Subject: [PATCH 252/307] Typos found by codespell (#607) --- cJSON.h | 2 +- tests/json_patch_tests.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cJSON.h b/cJSON.h index e97e5f4c..b7b069a2 100644 --- a/cJSON.h +++ b/cJSON.h @@ -256,7 +256,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons /* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. * The input pointer json cannot point to a read-only address area, such as a string constant, - * but should point to a readable and writable adress area. */ + * but should point to a readable and writable address area. */ CJSON_PUBLIC(void) cJSON_Minify(char *json); /* Helper functions for creating and adding items to an object at the same time. diff --git a/tests/json_patch_tests.c b/tests/json_patch_tests.c index c2c88a4f..7c3d6aed 100644 --- a/tests/json_patch_tests.c +++ b/tests/json_patch_tests.c @@ -66,7 +66,7 @@ static cJSON_bool test_apply_patch(const cJSON * const test) } else { - printf("Testing unkown\n"); + printf("Testing unknown\n"); } disabled = cJSON_GetObjectItemCaseSensitive(test, "disabled"); From 744e47353accda69c4d2f3d022eeacbf7b7d463e Mon Sep 17 00:00:00 2001 From: Alan Wang <948467222@qq.com> Date: Wed, 25 Aug 2021 15:02:00 +0800 Subject: [PATCH 253/307] fix: remove redundant condition (#605) --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 030311ce..04c37f62 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2976,7 +2976,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) { - if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) { return false; } From d348621ca93571343a56862df7de4ff3bc9b5667 Mon Sep 17 00:00:00 2001 From: Alan Wang <948467222@qq.com> Date: Wed, 25 Aug 2021 19:15:09 +0800 Subject: [PATCH 254/307] chore: update version and changelog (#610) --- CHANGELOG.md | 10 ++++++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff0f5b2d..ef5325de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +1.7.15 (Aug 25, 2021) +====== +Fixes: +------ +* Fix potential core dumped for strrchr, see [#546](https://github.com/DaveGamble/cJSON/pull/546) +* Fix null pointer crash in cJSON_CreateXxArray, see [#538](https://github.com/DaveGamble/cJSON/pull/538) +* Fix several null pointer problems on allocation failure, see [#526](https://github.com/DaveGamble/cJSON/pull/526) +* Fix a possible dereference of null pointer, see [#519](https://github.com/DaveGamble/cJSON/pull/519) +* Fix windows build failure about defining nan, see [#518](https://github.com/DaveGamble/cJSON/pull/518) + 1.7.14 (Sep 3, 2020) ====== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index e8c96342..7aecd98e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 14) +set(PROJECT_VERSION_PATCH 15) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") diff --git a/Makefile b/Makefile index b1432305..3bc04ae2 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.14 +LIBVERSION = 1.7.15 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 04c37f62..3063f74e 100644 --- a/cJSON.c +++ b/cJSON.c @@ -117,7 +117,7 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 15) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index b7b069a2..92907a2c 100644 --- a/cJSON.h +++ b/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 14 +#define CJSON_VERSION_PATCH 15 #include From f50dafc7d0bfd4f45449ab5665bfea831a82f2eb Mon Sep 17 00:00:00 2001 From: Alan Wang <948467222@qq.com> Date: Thu, 26 Aug 2021 14:13:42 +0800 Subject: [PATCH 255/307] fix: potential memory leak in merge_patch() (#611) --- cJSON_Utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index c7c64391..63651dfb 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -1367,6 +1367,7 @@ static cJSON *merge_patch(cJSON *target, const cJSON * const patch, const cJSON_ replacement = merge_patch(replace_me, patch_child, case_sensitive); if (replacement == NULL) { + cJSON_Delete(target); return NULL; } From b9eff8b02afd0e2612b695fb8d67d56839b126ce Mon Sep 17 00:00:00 2001 From: Sayan Bandyopadhyay Date: Fri, 22 Oct 2021 00:57:05 -0700 Subject: [PATCH 256/307] fix: for issue #569, now use the guard to turn it off (#617) --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7aecd98e..03c97167 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -255,7 +255,11 @@ if(ENABLE_CJSON_TEST) endif() #Create the uninstall target -add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${PROJECT_SOURCE_DIR}/library_config/uninstall.cmake") +option(ENABLE_CJSON_UNINSTALL "Enable creating uninstall target" ON) +if(ENABLE_CJSON_UNINSTALL) + add_custom_target(uninstall "${CMAKE_COMMAND}" -P + "${PROJECT_SOURCE_DIR}/library_config/uninstall.cmake") +endif() # Enable the use of locales option(ENABLE_LOCALES "Enable the use of locales" ON) From 189dcde644a08f3e26af9663511b3373f8f2d73c Mon Sep 17 00:00:00 2001 From: SuperHuan Date: Fri, 22 Oct 2021 16:02:06 +0800 Subject: [PATCH 257/307] fix: add cmake_policy to CMakeLists.txt (#613) Use the cmake_policy() command to set CMP0054 to NEW explicitly. --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 03c97167..acb1e88e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0) cmake_minimum_required(VERSION 2.8.5) project(cJSON C) +cmake_policy(SET CMP0054 NEW) # 设置 CMP0054 策略 include(GNUInstallDirs) From e5dbaee1316d0b36e8e120b4420c9b92352057a5 Mon Sep 17 00:00:00 2001 From: Alan Wang Date: Fri, 22 Oct 2021 16:09:45 +0800 Subject: [PATCH 258/307] docs: update comment (#622) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index acb1e88e..7b4520e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0) cmake_minimum_required(VERSION 2.8.5) project(cJSON C) -cmake_policy(SET CMP0054 NEW) # 设置 CMP0054 策略 +cmake_policy(SET CMP0054 NEW) # set CMP0054 policy include(GNUInstallDirs) From c77a68892761a1f4b1d5aadec72434615fcd1d85 Mon Sep 17 00:00:00 2001 From: Joshua Arulsamy Date: Fri, 22 Oct 2021 02:15:19 -0600 Subject: [PATCH 259/307] build: Bump cmake version and use new version syntax (#587) Co-authored-by: Alan Wang --- CMakeLists.txt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b4520e9..c26acbef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,18 +1,16 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0) -cmake_minimum_required(VERSION 2.8.5) +cmake_minimum_required(VERSION 3.0) + +project(cJSON + VERSION 1.7.15 + LANGUAGES C) -project(cJSON C) cmake_policy(SET CMP0054 NEW) # set CMP0054 policy include(GNUInstallDirs) -set(PROJECT_VERSION_MAJOR 1) -set(PROJECT_VERSION_MINOR 7) -set(PROJECT_VERSION_PATCH 15) set(CJSON_VERSION_SO 1) set(CJSON_UTILS_VERSION_SO 1) -set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") - set(custom_compiler_flags) From 203a0dec6ff06e3842fa23a1bc9825aecf56b381 Mon Sep 17 00:00:00 2001 From: Alan Wang Date: Fri, 22 Oct 2021 16:21:55 +0800 Subject: [PATCH 260/307] chore: ignore *.lst/*.lss file (#623) --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 58edf92c..b3c8d6b4 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ libcjson_utils.so.* .vscode .idea cmake-build-debug +*.lst +*.lss From d321fa9e6e574ff93518f6384865b9af0a4a4afc Mon Sep 17 00:00:00 2001 From: AlexanderVasiljev <48011002+AlexanderVasiljev@users.noreply.github.com> Date: Wed, 19 Jan 2022 05:30:31 +0300 Subject: [PATCH 261/307] fix: print int without decimal places (#630) --- cJSON.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cJSON.c b/cJSON.c index 3063f74e..c78aac66 100644 --- a/cJSON.c +++ b/cJSON.c @@ -562,6 +562,10 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out { length = sprintf((char*)number_buffer, "null"); } + else if(d == (double)item->valueint) + { + length = sprintf((char*)number_buffer, "%d", item->valueint); + } else { /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ From 61eb84d991cede2d6331a1222f872a93a054ace5 Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 19 Jan 2022 14:45:02 +0800 Subject: [PATCH 262/307] add an option for ENABLE_CJSON_VERSION_SO in CMakeLists.txt (#534) Co-authored-by: m00209177 --- CMakeLists.txt | 21 +++++++++++++-------- README.md | 1 + 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c26acbef..661502d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,7 @@ set(SOURCES cJSON.c) option(BUILD_SHARED_AND_STATIC_LIBS "Build both shared and static libraries" Off) option(CJSON_OVERRIDE_BUILD_SHARED_LIBS "Override BUILD_SHARED_LIBS with CJSON_BUILD_SHARED_LIBS" OFF) option(CJSON_BUILD_SHARED_LIBS "Overrides BUILD_SHARED_LIBS if CJSON_OVERRIDE_BUILD_SHARED_LIBS is enabled" ON) +option(ENABLE_CJSON_VERSION_SO "Enables cJSON so version" ON) if ((CJSON_OVERRIDE_BUILD_SHARED_LIBS AND CJSON_BUILD_SHARED_LIBS) OR ((NOT CJSON_OVERRIDE_BUILD_SHARED_LIBS) AND BUILD_SHARED_LIBS)) set(CJSON_LIBRARY_TYPE SHARED) @@ -162,10 +163,12 @@ if(ENABLE_TARGET_EXPORT) install(EXPORT "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON") endif() -set_target_properties("${CJSON_LIB}" - PROPERTIES - SOVERSION "${CJSON_VERSION_SO}" - VERSION "${PROJECT_VERSION}") +if(ENABLE_CJSON_VERSION_SO) + set_target_properties("${CJSON_LIB}" + PROPERTIES + SOVERSION "${CJSON_VERSION_SO}" + VERSION "${PROJECT_VERSION}") +endif() #cJSON_Utils option(ENABLE_CJSON_UTILS "Enable building the cJSON_Utils library." OFF) @@ -207,10 +210,12 @@ if(ENABLE_CJSON_UTILS) install(EXPORT "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON") endif() - set_target_properties("${CJSON_UTILS_LIB}" - PROPERTIES - SOVERSION "${CJSON_UTILS_VERSION_SO}" - VERSION "${PROJECT_VERSION}") + if(ENABLE_CJSON_VERSION_SO) + set_target_properties("${CJSON_UTILS_LIB}" + PROPERTIES + SOVERSION "${CJSON_UTILS_VERSION_SO}" + VERSION "${PROJECT_VERSION}") + endif() endif() # create the other package config files diff --git a/README.md b/README.md index cd18c7c5..0ea89da5 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,7 @@ You can change the build process with a list of different options that you can p * `-DCMAKE_INSTALL_PREFIX=/usr`: Set a prefix for the installation. * `-DENABLE_LOCALES=On`: Enable the usage of localeconv method. ( on by default ) * `-DCJSON_OVERRIDE_BUILD_SHARED_LIBS=On`: Enable overriding the value of `BUILD_SHARED_LIBS` with `-DCJSON_BUILD_SHARED_LIBS`. +* `-DENABLE_CJSON_VERSION_SO`: Enable cJSON so version. ( on by default ) If you are packaging cJSON for a distribution of Linux, you would probably take these steps for example: ``` From e7ebe77ebfb1251e0ea33086efaa82ac038c4e0c Mon Sep 17 00:00:00 2001 From: 10km <10km0811@sohu.com> Date: Wed, 19 Jan 2022 16:28:29 +0800 Subject: [PATCH 263/307] fix: 'cjson_utils-static' target not exist(#625) * Update CMakeLists.txt fix the bug:when build with cmake using option '-DBUILD_SHARED_AND_STATIC_LIBS=ON -DENABLE_CJSON_UTILS=ON', build sucess, but use cmake comand 'find_package(cjson CONFIG)', 'cjson_utils' target is available,but 'cjson_utils-static' target not exist. --- CMakeLists.txt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 661502d5..2d34969d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -156,7 +156,11 @@ install(TARGETS "${CJSON_LIB}" INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}" ) if (BUILD_SHARED_AND_STATIC_LIBS) - install(TARGETS "${CJSON_LIB}-static" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}") + install(TARGETS "${CJSON_LIB}-static" + EXPORT "${CJSON_LIB}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}" +) endif() if(ENABLE_TARGET_EXPORT) # export library information for CMake projects @@ -201,7 +205,11 @@ if(ENABLE_CJSON_UTILS) INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}" ) if (BUILD_SHARED_AND_STATIC_LIBS) - install(TARGETS "${CJSON_UTILS_LIB}-static" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}") + install(TARGETS "${CJSON_UTILS_LIB}-static" + EXPORT "${CJSON_UTILS_LIB}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}" + ) endif() install(FILES cJSON_Utils.h DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/cjson") install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig") From c7025b093aafec4da590638afe8453fee1899a97 Mon Sep 17 00:00:00 2001 From: Tony Langhammer Date: Thu, 20 Jan 2022 07:17:46 +0100 Subject: [PATCH 264/307] chore: ignore all .dylib files (#628) This fixes some .dylib files being flagged as added when compiled e.g. `libcjson.dylib.1.7.14` --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b3c8d6b4..65fa89b6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ test *.swp *.patch tags -*.dylib +*.dylib* build/ cJSON_test cJSON_test_utils From 2fc55f6793ff6a427e795cf3b8a68a534afb78a2 Mon Sep 17 00:00:00 2001 From: Randy Date: Thu, 20 Jan 2022 07:23:57 +0100 Subject: [PATCH 265/307] chore: add CIFuzz integration (#437) * CIFuzz integration * Rename main.yml to ci-fuzz.yml --- .github/workflows/ci-fuzz.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/ci-fuzz.yml diff --git a/.github/workflows/ci-fuzz.yml b/.github/workflows/ci-fuzz.yml new file mode 100644 index 00000000..36d89fbd --- /dev/null +++ b/.github/workflows/ci-fuzz.yml @@ -0,0 +1,23 @@ +name: CIFuzz +on: [pull_request] +jobs: + Fuzzing: + runs-on: ubuntu-latest + steps: + - name: Build Fuzzers + uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master + with: + oss-fuzz-project-name: 'cjson' + dry-run: false + - name: Run Fuzzers + uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master + with: + oss-fuzz-project-name: 'cjson' + fuzz-seconds: 600 + dry-run: false + - name: Upload Crash + uses: actions/upload-artifact@v1 + if: failure() + with: + name: artifacts + path: ./out/artifacts From 3cecc404664860bb4edbd9563b511bdf009d57ad Mon Sep 17 00:00:00 2001 From: mohawk2 Date: Wed, 26 Jan 2022 12:23:33 +0000 Subject: [PATCH 266/307] docs: Fix README typo (#664) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ea89da5..ebd32c4b 100644 --- a/README.md +++ b/README.md @@ -407,7 +407,7 @@ end: } ``` -Alternatively we can use the `cJSON_Add...ToObject` helper functions to make our lifes a little easier: +Alternatively we can use the `cJSON_Add...ToObject` helper functions to make our lives a little easier: ```c //NOTE: Returns a heap allocated string, you are required to free it after use. From a6424b85dde200a87cac26451c6f0a6f3426681f Mon Sep 17 00:00:00 2001 From: Stoian Ivanov Date: Wed, 26 Jan 2022 14:24:50 +0200 Subject: [PATCH 267/307] feat: add cJSON_SetBoolValue and test (#639) * cJSON_SetBoolValue plus test * cJSON_Invalid insted of just 0 * Update tests/misc_tests.c * VSCode standard C formater applied Co-authored-by: Alan Wang --- cJSON.h | 7 ++++ tests/misc_tests.c | 95 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/cJSON.h b/cJSON.h index 92907a2c..95a9cf69 100644 --- a/cJSON.h +++ b/cJSON.h @@ -279,6 +279,13 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double 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); +/* 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) ( \ + (object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \ + (object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \ + cJSON_Invalid\ +) + /* Macro for iterating over an array or object */ #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 3bf0a1cc..19b7c853 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -28,7 +28,6 @@ #include "unity/src/unity.h" #include "common.h" - static void cjson_array_foreach_should_loop_over_arrays(void) { cJSON array[1]; @@ -77,7 +76,6 @@ static void cjson_get_object_item_should_get_object_items(void) found = cJSON_GetObjectItem(item, NULL); TEST_ASSERT_NULL_MESSAGE(found, "Failed to fail on NULL string."); - found = cJSON_GetObjectItem(item, "one"); TEST_ASSERT_NOT_NULL_MESSAGE(found, "Failed to find first item."); TEST_ASSERT_EQUAL_DOUBLE(found->valuedouble, 1); @@ -127,7 +125,8 @@ static void cjson_get_object_item_case_sensitive_should_get_object_items(void) cJSON_Delete(item); } -static void cjson_get_object_item_should_not_crash_with_array(void) { +static void cjson_get_object_item_should_not_crash_with_array(void) +{ cJSON *array = NULL; cJSON *found = NULL; array = cJSON_Parse("[1]"); @@ -138,7 +137,8 @@ static void cjson_get_object_item_should_not_crash_with_array(void) { cJSON_Delete(array); } -static void cjson_get_object_item_case_sensitive_should_not_crash_with_array(void) { +static void cjson_get_object_item_case_sensitive_should_not_crash_with_array(void) +{ cJSON *array = NULL; cJSON *found = NULL; array = cJSON_Parse("[1]"); @@ -302,7 +302,6 @@ static void cjson_replace_item_via_pointer_should_replace_items(void) cJSON_AddItemToArray(array, middle); cJSON_AddItemToArray(array, end); - memset(replacements, '\0', sizeof(replacements)); /* replace beginning */ @@ -329,7 +328,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, NULL}}; cJSON *child = NULL; cJSON *replacement = NULL; cJSON_bool flag = false; @@ -339,7 +338,7 @@ static void cjson_replace_item_in_object_should_preserve_name(void) replacement = cJSON_CreateNumber(2); TEST_ASSERT_NOT_NULL(replacement); - flag = cJSON_AddItemToObject(root, "child", child); + flag = cJSON_AddItemToObject(root, "child", child); TEST_ASSERT_TRUE_MESSAGE(flag, "add item to object failed"); cJSON_ReplaceItemInObject(root, "child", replacement); @@ -435,7 +434,7 @@ static void cjson_functions_should_not_crash_with_null_pointers(void) cJSON_Delete(item); } -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)pointer; @@ -445,7 +444,7 @@ static void * CJSON_CDECL failing_realloc(void *pointer, size_t size) static void ensure_should_fail_on_failed_realloc(void) { printbuffer buffer = {NULL, 10, 0, 0, false, false, {&malloc, &free, &failing_realloc}}; - buffer.buffer = (unsigned char*)malloc(100); + buffer.buffer = (unsigned char *)malloc(100); TEST_ASSERT_NOT_NULL(buffer.buffer); TEST_ASSERT_NULL_MESSAGE(ensure(&buffer, 200), "Ensure didn't fail with failing realloc."); @@ -454,7 +453,7 @@ static void ensure_should_fail_on_failed_realloc(void) static void skip_utf8_bom_should_skip_bom(void) { const unsigned char string[] = "\xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + parse_buffer buffer = {0, 0, 0, 0, {0, 0, 0}}; buffer.content = string; buffer.length = sizeof(string); buffer.hooks = global_hooks; @@ -466,7 +465,7 @@ static void skip_utf8_bom_should_skip_bom(void) static void skip_utf8_bom_should_not_skip_bom_if_not_at_beginning(void) { const unsigned char string[] = " \xEF\xBB\xBF{}"; - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + parse_buffer buffer = {0, 0, 0, 0, {0, 0, 0}}; buffer.content = string; buffer.length = sizeof(string); buffer.hooks = global_hooks; @@ -496,12 +495,13 @@ static void cjson_get_number_value_should_get_a_number(void) TEST_ASSERT_EQUAL_DOUBLE(cJSON_GetNumberValue(number), number->valuedouble); TEST_ASSERT_DOUBLE_IS_NAN(cJSON_GetNumberValue(string)); TEST_ASSERT_DOUBLE_IS_NAN(cJSON_GetNumberValue(NULL)); - + cJSON_Delete(number); cJSON_Delete(string); } -static void cjson_create_string_reference_should_create_a_string_reference(void) { +static void cjson_create_string_reference_should_create_a_string_reference(void) +{ const char *string = "I am a string!"; cJSON *string_reference = cJSON_CreateStringReference(string); @@ -511,7 +511,8 @@ static void cjson_create_string_reference_should_create_a_string_reference(void) cJSON_Delete(string_reference); } -static void cjson_create_object_reference_should_create_an_object_reference(void) { +static void cjson_create_object_reference_should_create_an_object_reference(void) +{ cJSON *number_reference = NULL; cJSON *number_object = cJSON_CreateObject(); cJSON *number = cJSON_CreateNumber(42); @@ -529,7 +530,8 @@ static void cjson_create_object_reference_should_create_an_object_reference(void cJSON_Delete(number_reference); } -static void cjson_create_array_reference_should_create_an_array_reference(void) { +static void cjson_create_array_reference_should_create_an_array_reference(void) +{ cJSON *number_reference = NULL; cJSON *number_array = cJSON_CreateArray(); cJSON *number = cJSON_CreateNumber(42); @@ -566,7 +568,7 @@ static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_al { cJSON *object = cJSON_CreateObject(); cJSON *number = cJSON_CreateNumber(42); - char *name = (char*)cJSON_strdup((const unsigned char*)"number", &global_hooks); + char *name = (char *)cJSON_strdup((const unsigned char *)"number", &global_hooks); TEST_ASSERT_NOT_NULL(object); TEST_ASSERT_NOT_NULL(number); @@ -626,7 +628,7 @@ static void cjson_set_valuestring_to_object_should_not_leak_memory(void) cJSON *item2 = cJSON_CreateStringReference(reference_valuestring); char *ptr1 = NULL; char *return_value = NULL; - + cJSON_AddItemToObject(root, "one", item1); cJSON_AddItemToObject(root, "two", item2); @@ -650,6 +652,64 @@ static void cjson_set_valuestring_to_object_should_not_leak_memory(void) cJSON_Delete(root); } +static void cjson_set_bool_value_must_not_break_objects(void) +{ + cJSON *bobj, *sobj, *oobj, *refobj = NULL; + + TEST_ASSERT_TRUE((cJSON_SetBoolValue(refobj, 1) == cJSON_Invalid)); + + bobj = cJSON_CreateFalse(); + TEST_ASSERT_TRUE(cJSON_IsFalse(bobj)); + TEST_ASSERT_TRUE((cJSON_SetBoolValue(bobj, 1) == cJSON_True)); + TEST_ASSERT_TRUE(cJSON_IsTrue(bobj)); + cJSON_SetBoolValue(bobj, 1); + TEST_ASSERT_TRUE(cJSON_IsTrue(bobj)); + TEST_ASSERT_TRUE((cJSON_SetBoolValue(bobj, 0) == cJSON_False)); + TEST_ASSERT_TRUE(cJSON_IsFalse(bobj)); + cJSON_SetBoolValue(bobj, 0); + TEST_ASSERT_TRUE(cJSON_IsFalse(bobj)); + + sobj = cJSON_CreateString("test"); + TEST_ASSERT_TRUE(cJSON_IsString(sobj)); + cJSON_SetBoolValue(sobj, 1); + TEST_ASSERT_TRUE(cJSON_IsString(sobj)); + cJSON_SetBoolValue(sobj, 0); + TEST_ASSERT_TRUE(cJSON_IsString(sobj)); + + oobj = cJSON_CreateObject(); + TEST_ASSERT_TRUE(cJSON_IsObject(oobj)); + cJSON_SetBoolValue(oobj, 1); + TEST_ASSERT_TRUE(cJSON_IsObject(oobj)); + cJSON_SetBoolValue(oobj, 0); + TEST_ASSERT_TRUE(cJSON_IsObject(oobj)); + + refobj = cJSON_CreateStringReference("conststring"); + TEST_ASSERT_TRUE(cJSON_IsString(refobj)); + TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference); + cJSON_SetBoolValue(refobj, 1); + TEST_ASSERT_TRUE(cJSON_IsString(refobj)); + TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference); + cJSON_SetBoolValue(refobj, 0); + TEST_ASSERT_TRUE(cJSON_IsString(refobj)); + TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference); + cJSON_Delete(refobj); + + refobj = cJSON_CreateObjectReference(oobj); + TEST_ASSERT_TRUE(cJSON_IsObject(refobj)); + TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference); + cJSON_SetBoolValue(refobj, 1); + TEST_ASSERT_TRUE(cJSON_IsObject(refobj)); + TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference); + cJSON_SetBoolValue(refobj, 0); + TEST_ASSERT_TRUE(cJSON_IsObject(refobj)); + TEST_ASSERT_TRUE(refobj->type & cJSON_IsReference); + cJSON_Delete(refobj); + + cJSON_Delete(oobj); + cJSON_Delete(bobj); + cJSON_Delete(sobj); +} + int CJSON_CDECL main(void) { UNITY_BEGIN(); @@ -679,6 +739,7 @@ int CJSON_CDECL main(void) RUN_TEST(cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased); 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_bool_value_must_not_break_objects); return UNITY_END(); } From b45f48e600671feade0b6bd65d1c69de7899f2be Mon Sep 17 00:00:00 2001 From: Junbo Zheng <3273070@qq.com> Date: Tue, 29 Mar 2022 15:02:59 +0800 Subject: [PATCH 268/307] fix: add allocate check for replace_item_in_object (#675) Signed-off-by: Junbo Zheng --- cJSON.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/cJSON.c b/cJSON.c index c78aac66..524ba464 100644 --- a/cJSON.c +++ b/cJSON.c @@ -96,9 +96,9 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) return (const char*) (global_error.json + global_error.position); } -CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) +CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) { - if (!cJSON_IsString(item)) + if (!cJSON_IsString(item)) { return NULL; } @@ -106,9 +106,9 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) return item->valuestring; } -CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) +CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) { - if (!cJSON_IsNumber(item)) + if (!cJSON_IsNumber(item)) { return (double) NAN; } @@ -511,7 +511,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) return NULL; } - + memcpy(newbuffer, p->buffer, p->offset + 1); p->hooks.deallocate(p->buffer); } @@ -1107,7 +1107,7 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer } buffer.content = (const unsigned char*)value; - buffer.length = buffer_length; + buffer.length = buffer_length; buffer.offset = 0; buffer.hooks = global_hooks; @@ -2361,6 +2361,11 @@ static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSO cJSON_free(replacement->string); } replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if (replacement->string == NULL) + { + return false; + } + replacement->type &= ~cJSON_StringIsConst; return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); @@ -2693,7 +2698,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int co if (a && a->child) { a->child->prev = n; } - + return a; } From 766dd9d590bfbda32e6f77bff096c15eebffa3f0 Mon Sep 17 00:00:00 2001 From: hopper-vul <118949689+hopper-vul@users.noreply.github.com> Date: Sat, 1 Jul 2023 16:18:32 +0800 Subject: [PATCH 269/307] Fix a null pointer crash in cJSON_ReplaceItemViaPointer (#726) If the parent passed in cJSON_ReplaceItemViaPointer has not a child, which means parent->child is null, a null pointer dereference crash will be happened inside cJSON_ReplaceItemViaPointer. This commit adds the NULL check of `parent->child` beforehand to inform user such incorrect usage. Signed-off-by: hopper-vul --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 524ba464..d7aeecd9 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2291,7 +2291,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) { - if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + if ((parent == NULL) || (parent->child == NULL) || (replacement == NULL) || (item == NULL)) { return false; } From 543c28869e4b215522635b7270b4b7cbb43030af Mon Sep 17 00:00:00 2001 From: MaxBrandtner Date: Mon, 3 Jul 2023 03:35:30 +0200 Subject: [PATCH 270/307] Add meson documentation (#761) --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index ebd32c4b..99147afd 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Ultralightweight JSON parser in ANSI C. * [Copying the source](#copying-the-source) * [CMake](#cmake) * [Makefile](#makefile) + * [Meson](#meson) * [Vcpkg](#Vcpkg) * [Including cJSON](#including-cjson) * [Data Structure](#data-structure) @@ -145,6 +146,23 @@ make all If you want, you can install the compiled library to your system using `make install`. By default it will install the headers in `/usr/local/include/cjson` and the libraries in `/usr/local/lib`. But you can change this behavior by setting the `PREFIX` and `DESTDIR` variables: `make PREFIX=/usr DESTDIR=temp install`. And uninstall them with: `make PREFIX=/usr DESTDIR=temp uninstall`. +#### Meson + +To make cjson work in a project using meson, the libcjson dependency has to be included: + +```meson +project('c-json-example', 'c') + +cjson = dependency('libcjson') + +example = executable( + 'example', + 'example.c', + dependencies: [cjson], +) +``` + + #### Vcpkg You can download and install cJSON using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: From 545710e3bfff09f875222b003de9044699769301 Mon Sep 17 00:00:00 2001 From: Alan Wang Date: Tue, 4 Jul 2023 17:02:03 +0800 Subject: [PATCH 271/307] upgrade clang to fix actions error (#768) Actions builds are failing because clang-8 is failing to be installed. Upgrade clang-8 to clang-14 to fix this. --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index dc9d17c6..b06ab11d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -31,7 +31,7 @@ jobs: - name: install build dependencies run: | sudo apt-get update - sudo apt-get install clang-8 valgrind + sudo apt-get install clang-14 valgrind - name: build and test shell: bash run: | From cb8693b058ba302f4829ec6d03f609ac6f848546 Mon Sep 17 00:00:00 2001 From: Alan Wang Date: Wed, 5 Jul 2023 11:22:19 +0800 Subject: [PATCH 272/307] Release 1.7.16 (#770) * Update version to 1.7.16 * Update contributors --- CHANGELOG.md | 19 +++++++++++++++++++ CMakeLists.txt | 2 +- CONTRIBUTORS.md | 12 ++++++++++++ Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 6 files changed, 35 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef5325de..85fa40cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +1.7.16 (Jul 5, 2023) +====== +Features: +------ +* Add an option for ENABLE_CJSON_VERSION_SO in CMakeLists.txt, see #534 +* Add cmake_policy to CMakeLists.txt, see #163 +* Add cJSON_SetBoolValue, see #639 +* Add meson documentation, see #761 + +Fixes: +------ +* Fix memory leak in merge_patch, see #611 +* Fix conflicting target names 'uninstall', see #617 +* Bump cmake version to 3.0 and use new version syntax, see #587 +* Print int without decimal places, see #630 +* Fix 'cjson_utils-static' target not exist, see #625 +* Add allocate check for replace_item_in_object, see #675 +* Fix a null pointer crash in cJSON_ReplaceItemViaPointer, see #726 + 1.7.15 (Aug 25, 2021) ====== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d34969d..f23ec631 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0) cmake_minimum_required(VERSION 3.0) project(cJSON - VERSION 1.7.15 + VERSION 1.7.16 LANGUAGES C) cmake_policy(SET CMP0054 NEW) # set CMP0054 policy diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index f113ab22..a9a42c89 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -10,8 +10,10 @@ Current Maintainer: Contributors: * [Ajay Bhargav](https://github.com/ajaybhargav) +* [AlexanderVasiljev](https://github.com/AlexanderVasiljev) * [Alper Akcan](https://github.com/alperakcan) * [Andrew Tang](https://github.com/singku) +* [Andy](https://github.com/mlh0101) * [Anton Sergeev](https://github.com/anton-sergeev) * [Benbuck Nason](https://github.com/bnason-nf) * [Bernt Johan Damslora](https://github.com/bjda) @@ -29,20 +31,25 @@ Contributors: * [Fabrice Fontaine](https://github.com/ffontaine) * Ian Mobley * Irwan Djadjadi +* [hopper-vul](https://github.com/hopper-vul) * [HuKeping](https://github.com/HuKeping) * [IvanVoid](https://github.com/npi3pak) * [Jakub Wilk](https://github.com/jwilk) * [Jiri Zouhar](https://github.com/loigu) * [Jonathan Fether](https://github.com/jfether) +* [Joshua Arulsamy](https://github.com/jarulsamy) * [Julian Ste](https://github.com/julian-st) * [Julián Vásquez](https://github.com/juvasquezg) +* [Junbo Zheng](https://github.com/Junbo-Zheng) * [Kevin Branigan](https://github.com/kbranigan) * [Kevin Sapper](https://github.com/sappo) * [Kyle Chisholm](https://github.com/ChisholmKyle) * [Linus Wallgren](https://github.com/ecksun) +* [MaxBrandtner](https://github.com/MaxBrandtner) * [Mateusz Szafoni](https://github.com/raiden00pl) * Mike Pontillo * [miaoerduo](https://github.com/miaoerduo) +* [mohawk2](https://github.com/mohawk2) * [Mike Jerris](https://github.com/mjerris) * [Mike Robinson](https://github.com/mhrobinson) * [Moorthy](https://github.com/moorthy-bs) @@ -61,10 +68,14 @@ Contributors: * [Romain Porte](https://github.com/MicroJoe) * [SANJEEV BA](https://github.com/basanjeev) * [Sang-Heon Jeon](https://github.com/lntuition) +* [Sayan Bandyopadhyay](https://github.com/saynb) * [Simon Sobisch](https://github.com/GitMensch) * [Simon Ricaldone](https://github.com/simon-p-r) +* [Stoian Ivanov](https://github.com/sdrsdr) +* [SuperH-0630](https://github.com/SuperH-0630) * [Square789](https://github.com/Square789) * [Stephan Gatzka](https://github.com/gatzka) +* [Tony Langhammer](https://github.com/BigBrainAFK) * [Vemake](https://github.com/vemakereporter) * [Wei Tan](https://github.com/tan-wei) * [Weston Schmidt](https://github.com/schmidtw) @@ -73,6 +84,7 @@ Contributors: * [yuta-oxo](https://github.com/yuta-oxo) * [Zach Hindes](https://github.com/zhindes) * [Zhao Zhixu](https://github.com/zhaozhixu) +* [10km](https://github.com/10km) And probably more people on [SourceForge](https://sourceforge.net/p/cjson/bugs/search/?q=status%3Aclosed-rejected+or+status%3Aclosed-out-of-date+or+status%3Awont-fix+or+status%3Aclosed-fixed+or+status%3Aclosed&page=0) diff --git a/Makefile b/Makefile index 3bc04ae2..40b61527 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.15 +LIBVERSION = 1.7.16 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index d7aeecd9..f6dd11c5 100644 --- a/cJSON.c +++ b/cJSON.c @@ -117,7 +117,7 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 15) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 16) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 95a9cf69..2628d763 100644 --- a/cJSON.h +++ b/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 15 +#define CJSON_VERSION_PATCH 16 #include From 60ff122ef5862d04b39b150541459e7f5e35add8 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 18 Dec 2023 11:47:52 +0800 Subject: [PATCH 273/307] add NULL checkings (#809) * add NULL checks in cJSON_SetValuestring Fixes #803(CVE-2023-50472) * add NULL check in cJSON_InsertItemInArray Fixes #802(CVE-2023-50471) * add tests for NULL checks add tests for NULL checks in cJSON_InsertItemInArray and cJSON_SetValuestring --- cJSON.c | 14 ++++++++++++-- tests/misc_tests.c | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index f6dd11c5..faa3e297 100644 --- a/cJSON.c +++ b/cJSON.c @@ -401,7 +401,12 @@ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) { char *copy = NULL; /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ - if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) + if ((object == NULL) || !(object->type & cJSON_String) || (object->type & cJSON_IsReference)) + { + return NULL; + } + /* return NULL if the object is corrupted */ + if (object->valuestring == NULL) { return NULL; } @@ -2264,7 +2269,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON { cJSON *after_inserted = NULL; - if (which < 0) + if (which < 0 || newitem == NULL) { return false; } @@ -2275,6 +2280,11 @@ CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON return add_item_to_array(array, newitem); } + if (after_inserted != array->child && newitem->prev == NULL) { + /* return false if after_inserted is a corrupted array item */ + return false; + } + newitem->next = after_inserted; newitem->prev = after_inserted->prev; after_inserted->prev = newitem; diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 19b7c853..48fb6ec2 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -352,6 +352,19 @@ static void cjson_functions_should_not_crash_with_null_pointers(void) { char buffer[10]; cJSON *item = cJSON_CreateString("item"); + cJSON *array = cJSON_CreateArray(); + cJSON *item1 = cJSON_CreateString("item1"); + cJSON *item2 = cJSON_CreateString("corrupted array item3"); + cJSON *corruptedString = cJSON_CreateString("corrupted"); + struct cJSON *originalPrev; + + add_item_to_array(array, item1); + add_item_to_array(array, item2); + + originalPrev = item2->prev; + item2->prev = NULL; + free(corruptedString->valuestring); + corruptedString->valuestring = NULL; cJSON_InitHooks(NULL); TEST_ASSERT_NULL(cJSON_Parse(NULL)); @@ -411,6 +424,8 @@ static void cjson_functions_should_not_crash_with_null_pointers(void) cJSON_DeleteItemFromObject(item, NULL); cJSON_DeleteItemFromObjectCaseSensitive(NULL, "item"); cJSON_DeleteItemFromObjectCaseSensitive(item, NULL); + TEST_ASSERT_FALSE(cJSON_InsertItemInArray(array, 0, NULL)); + TEST_ASSERT_FALSE(cJSON_InsertItemInArray(array, 1, item)); TEST_ASSERT_FALSE(cJSON_InsertItemInArray(NULL, 0, item)); TEST_ASSERT_FALSE(cJSON_InsertItemInArray(item, 0, NULL)); TEST_ASSERT_FALSE(cJSON_ReplaceItemViaPointer(NULL, item, item)); @@ -427,10 +442,16 @@ static void cjson_functions_should_not_crash_with_null_pointers(void) TEST_ASSERT_NULL(cJSON_Duplicate(NULL, true)); TEST_ASSERT_FALSE(cJSON_Compare(item, NULL, false)); TEST_ASSERT_FALSE(cJSON_Compare(NULL, item, false)); + TEST_ASSERT_NULL(cJSON_SetValuestring(NULL, "test")); + TEST_ASSERT_NULL(cJSON_SetValuestring(corruptedString, "test")); cJSON_Minify(NULL); /* skipped because it is only used via a macro that checks for NULL */ /* cJSON_SetNumberHelper(NULL, 0); */ + /* restore corrupted item2 to delete it */ + item2->prev = originalPrev; + cJSON_Delete(corruptedString); + cJSON_Delete(array); cJSON_Delete(item); } From f66cbab4bfb3926ffd4c5e13f9fb6d506ee0241d Mon Sep 17 00:00:00 2001 From: Lee Date: Wed, 20 Dec 2023 11:05:23 +0800 Subject: [PATCH 274/307] fix error in null checkings (#810) fixes #802 and #803 --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index faa3e297..8411d947 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2280,7 +2280,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON return add_item_to_array(array, newitem); } - if (after_inserted != array->child && newitem->prev == NULL) { + if (after_inserted != array->child && after_inserted->prev == NULL) { /* return false if after_inserted is a corrupted array item */ return false; } From 87d8f0961a01bf09bef98ff89bae9fdec42181ee Mon Sep 17 00:00:00 2001 From: Alanscut Date: Tue, 26 Dec 2023 10:07:05 +0800 Subject: [PATCH 275/307] Release 1.7.17 update version to 1.7.17 --- CHANGELOG.md | 7 +++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85fa40cc..51261ab5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +1.7.17 (Dec 26, 2023) +====== +Fixes: +------ +* Fix null reference in cJSON_SetValuestring(CVE-2023-50472), see #809 +* Fix null reference in cJSON_InsertItemInArray(CVE-2023-50471), see #809 and #810 + 1.7.16 (Jul 5, 2023) ====== Features: diff --git a/CMakeLists.txt b/CMakeLists.txt index f23ec631..0d807ea6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0) cmake_minimum_required(VERSION 3.0) project(cJSON - VERSION 1.7.16 + VERSION 1.7.17 LANGUAGES C) cmake_policy(SET CMP0054 NEW) # set CMP0054 policy diff --git a/Makefile b/Makefile index 40b61527..bc762e05 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.16 +LIBVERSION = 1.7.17 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 8411d947..4e4979e9 100644 --- a/cJSON.c +++ b/cJSON.c @@ -117,7 +117,7 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 16) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 17) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 2628d763..218cc9ea 100644 --- a/cJSON.h +++ b/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 16 +#define CJSON_VERSION_PATCH 17 #include From 7e4d5dabe7a9b754c601f214e65b544e67ba9f59 Mon Sep 17 00:00:00 2001 From: Up-wind Date: Mon, 25 Mar 2024 20:07:11 +0800 Subject: [PATCH 276/307] Add NULL check to cJSON_SetValuestring() If the valuestring passed to cJSON_SetValuestring is NULL, a null pointer dereference will happen. This commit adds the NULL check of valuestring before it is dereferenced. --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 4e4979e9..8903e4c2 100644 --- a/cJSON.c +++ b/cJSON.c @@ -406,7 +406,7 @@ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) return NULL; } /* return NULL if the object is corrupted */ - if (object->valuestring == NULL) + if (object->valuestring == NULL || valuestring == NULL) { return NULL; } From 66e9dff670a953586d4e75296f021a1c40f66768 Mon Sep 17 00:00:00 2001 From: Alan Wang Date: Fri, 26 Apr 2024 16:58:00 +0800 Subject: [PATCH 277/307] Create SECURITY.md --- SECURITY.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..6113832e --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,11 @@ +# Security Policy + +## Supported Versions + +Security is of the highest importance and all security vulnerabilities or suspected security vulnerabilities should be reported to mavonEditor team privately, to minimize attacks against current users of mavonEditor before they are fixed. Vulnerabilities will be investigated and patched on the next patch (or minor) release as soon as possible. This information could be kept entirely internal to the project. + +## Reporting a Vulnerability + +If you know of a publicly disclosed security vulnerability for mavonEditor, please IMMEDIATELY contact wp_scut@163.com and peterlee@apache.org to inform the mavonEditor Team. + +IMPORTANT: Do not file public issues on GitHub for security vulnerabilities. From 5671646e9779ef8fa35990a5084e7e472e024862 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Sun, 28 Apr 2024 09:53:34 +0800 Subject: [PATCH 278/307] fix: fix incorrect name in security.md Related to #845 --- SECURITY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 6113832e..33d99a2e 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,10 +2,10 @@ ## Supported Versions -Security is of the highest importance and all security vulnerabilities or suspected security vulnerabilities should be reported to mavonEditor team privately, to minimize attacks against current users of mavonEditor before they are fixed. Vulnerabilities will be investigated and patched on the next patch (or minor) release as soon as possible. This information could be kept entirely internal to the project. +Security is of the highest importance and all security vulnerabilities or suspected security vulnerabilities should be reported to cjson team privately, to minimize attacks against current users of cjson before they are fixed. Vulnerabilities will be investigated and patched on the next patch (or minor) release as soon as possible. This information could be kept entirely internal to the project. ## Reporting a Vulnerability -If you know of a publicly disclosed security vulnerability for mavonEditor, please IMMEDIATELY contact wp_scut@163.com and peterlee@apache.org to inform the mavonEditor Team. +If you know of a publicly disclosed security vulnerability for cjson, please IMMEDIATELY contact wp_scut@163.com and peterlee@apache.org to inform the cjson Team. IMPORTANT: Do not file public issues on GitHub for security vulnerabilities. From 19396a49a60a1937bc8cbf30ab5579f089ee2f0f Mon Sep 17 00:00:00 2001 From: Alanscut Date: Sun, 28 Apr 2024 18:09:25 +0800 Subject: [PATCH 279/307] update comments and add tests for cJSON_SetValuestring --- cJSON.c | 3 ++- tests/misc_tests.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 8903e4c2..4f5b38dc 100644 --- a/cJSON.c +++ b/cJSON.c @@ -397,6 +397,7 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) return object->valuedouble = 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) { char *copy = NULL; @@ -405,7 +406,7 @@ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) { return NULL; } - /* return NULL if the object is corrupted */ + /* return NULL if the object is corrupted or valuestring is NULL */ if (object->valuestring == NULL || valuestring == NULL) { return NULL; diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 48fb6ec2..ba3e003e 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -444,6 +444,7 @@ static void cjson_functions_should_not_crash_with_null_pointers(void) TEST_ASSERT_FALSE(cJSON_Compare(NULL, item, false)); TEST_ASSERT_NULL(cJSON_SetValuestring(NULL, "test")); TEST_ASSERT_NULL(cJSON_SetValuestring(corruptedString, "test")); + TEST_ASSERT_NULL(cJSON_SetValuestring(item, NULL)); cJSON_Minify(NULL); /* skipped because it is only used via a macro that checks for NULL */ /* cJSON_SetNumberHelper(NULL, 0); */ From 98f9eb0412067a852ec107c68e49180fe4e472dc Mon Sep 17 00:00:00 2001 From: orri Date: Tue, 30 Apr 2024 08:18:17 +0000 Subject: [PATCH 280/307] Remove non-functional list handling of compiler flags --- CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d807ea6..50fc3885 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,13 +102,10 @@ foreach(compiler_flag ${custom_compiler_flags}) CHECK_C_COMPILER_FLAG(${compiler_flag} "FLAG_SUPPORTED_${current_variable}") if (FLAG_SUPPORTED_${current_variable}) - list(APPEND supported_compiler_flags) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${compiler_flag}") endif() endforeach() -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${supported_compiler_flags}") - option(BUILD_SHARED_LIBS "Build shared libraries" ON) option(ENABLE_TARGET_EXPORT "Enable exporting of CMake targets. Disable when it causes problems!" ON) From 826cd6f842ae7e46ee38bbc097f9a34f2947388d Mon Sep 17 00:00:00 2001 From: orri Date: Tue, 30 Apr 2024 09:46:17 +0000 Subject: [PATCH 281/307] Add test for heap buffer overflow From #800 --- tests/parse_examples.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/parse_examples.c b/tests/parse_examples.c index 95a09590..d35d6cfb 100644 --- a/tests/parse_examples.c +++ b/tests/parse_examples.c @@ -250,6 +250,33 @@ static void test14_should_not_be_parsed(void) } } +/* Address Sanitizer */ +static void test15_should_not_heap_buffer_overflow(void) +{ + const char *strings[] = { + "{\"1\":1,", + "{\"1\":1, ", + }; + + size_t i; + + for (i = 0; i < sizeof(strings) / sizeof(strings[0]); i+=1) + { + const char *json_string = strings[i]; + size_t len = strlen(json_string); + cJSON *json = NULL; + + char *exact_size_heap = (char*)malloc(len); + TEST_ASSERT_NOT_NULL(exact_size_heap); + + memcpy(exact_size_heap, json_string, len); + json = cJSON_ParseWithLength(exact_size_heap, len); + + cJSON_Delete(json); + free(exact_size_heap); + } +} + int CJSON_CDECL main(void) { UNITY_BEGIN(); @@ -267,5 +294,6 @@ int CJSON_CDECL main(void) RUN_TEST(test12_should_not_be_parsed); RUN_TEST(test13_should_be_parsed_without_null_termination); RUN_TEST(test14_should_not_be_parsed); + RUN_TEST(test15_should_not_heap_buffer_overflow); return UNITY_END(); } From 3ef4e4e730e5efd381be612df41e1ff3f5bb3c32 Mon Sep 17 00:00:00 2001 From: orri Date: Tue, 30 Apr 2024 09:50:19 +0000 Subject: [PATCH 282/307] Fix heap buffer overflow Fixes #800 --- cJSON.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cJSON.c b/cJSON.c index 4f5b38dc..97564bb0 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1660,6 +1660,11 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu current_item = new_item; } + if (cannot_access_at_index(input_buffer, 1)) + { + goto fail; /* nothing comes after the comma */ + } + /* parse the name of the child */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); From a20be7996dbb05631fbc98ab48fa6be31fe5c275 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 9 May 2024 09:53:14 +0800 Subject: [PATCH 283/307] fix: remove misused optimization flag -01 related to #850 --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 50fc3885..1f204375 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,7 +70,6 @@ if (ENABLE_SANITIZERS) -fsanitize=float-cast-overflow -fsanitize-address-use-after-scope -fsanitize=integer - -01 -fno-sanitize-recover ) endif() From 542fb0eadd3db62630c1eb958e685f1d8e30694e Mon Sep 17 00:00:00 2001 From: maebex Date: Sat, 30 Mar 2024 10:42:22 +0100 Subject: [PATCH 284/307] Set free'd pointers to NULL whenever they are not reassigned immediately after --- cJSON.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cJSON.c b/cJSON.c index 97564bb0..6f55820f 100644 --- a/cJSON.c +++ b/cJSON.c @@ -263,10 +263,12 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) { global_hooks.deallocate(item->valuestring); + item->valuestring = NULL; } if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) { global_hooks.deallocate(item->string); + item->string = NULL; } global_hooks.deallocate(item); item = next; @@ -894,6 +896,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu if (output != NULL) { input_buffer->hooks.deallocate(output); + output = NULL; } if (input_pointer != NULL) @@ -1236,6 +1239,7 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i /* free the buffer */ hooks->deallocate(buffer->buffer); + buffer->buffer = NULL; } return printed; @@ -1244,11 +1248,13 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i if (buffer->buffer != NULL) { hooks->deallocate(buffer->buffer); + buffer->buffer = NULL; } if (printed != NULL) { hooks->deallocate(printed); + printed = NULL; } return NULL; @@ -1289,6 +1295,7 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON if (!print_value(item, &p)) { global_hooks.deallocate(p.buffer); + p.buffer = NULL; return NULL; } @@ -3132,4 +3139,5 @@ CJSON_PUBLIC(void *) cJSON_malloc(size_t size) CJSON_PUBLIC(void) cJSON_free(void *object) { global_hooks.deallocate(object); + object = NULL; } From 5b502cdbfb21fbe5f6cf9ffbd2b96e4281a741e6 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Thu, 9 May 2024 10:45:16 +0800 Subject: [PATCH 285/307] feat: add tests for #842 Add some tests for setting NULL to deallocated pointers releated to #842 and #833 --- tests/CMakeLists.txt | 1 + tests/misc_tests.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c7592213..9e8962f6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -62,6 +62,7 @@ if(ENABLE_CJSON_TEST) option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.") if (ENABLE_VALGRIND) + add_compile_definitions(ENABLE_VALGRIND) find_program(MEMORYCHECK_COMMAND valgrind) if ("${MEMORYCHECK_COMMAND}" MATCHES "MEMORYCHECK_COMMAND-NOTFOUND") message(WARNING "Valgrind couldn't be found.") diff --git a/tests/misc_tests.c b/tests/misc_tests.c index ba3e003e..94dd91aa 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -732,6 +732,23 @@ static void cjson_set_bool_value_must_not_break_objects(void) 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) { UNITY_BEGIN(); @@ -762,6 +779,7 @@ int CJSON_CDECL main(void) 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_bool_value_must_not_break_objects); + RUN_TEST(deallocated_pointers_should_be_set_to_null); return UNITY_END(); } From 76be8fcf15677ca7f6db7c770f5ae6bf8b41d78f Mon Sep 17 00:00:00 2001 From: Alanscut Date: Mon, 13 May 2024 17:38:26 +0800 Subject: [PATCH 286/307] Release 1.7.18 --- CHANGELOG.md | 10 ++++++++++ CMakeLists.txt | 2 +- Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51261ab5..de1d8e66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +1.7.18 (May 13, 2024) +====== +Fixes: +------ +* Add NULL check to cJSON_SetValuestring()(CVE-2024-31755), see #839 and #840 +* Remove non-functional list handling of compiler flags, see #851 +* Fix heap buffer overflow, see #852 +* remove misused optimization flag -01, see #854 +* Set free'd pointers to NULL whenever they are not reassigned immediately after, see #855 and #833 + 1.7.17 (Dec 26, 2023) ====== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f204375..36a6cb57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0) cmake_minimum_required(VERSION 3.0) project(cJSON - VERSION 1.7.17 + VERSION 1.7.18 LANGUAGES C) cmake_policy(SET CMP0054 NEW) # set CMP0054 policy diff --git a/Makefile b/Makefile index bc762e05..00ef8073 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.17 +LIBVERSION = 1.7.18 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index 6f55820f..61483d90 100644 --- a/cJSON.c +++ b/cJSON.c @@ -117,7 +117,7 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 17) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 18) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 218cc9ea..88cf0bcf 100644 --- a/cJSON.h +++ b/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 17 +#define CJSON_VERSION_PATCH 18 #include From acc76239bee01d8e9c858ae2cab296704e52d916 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Mon, 13 May 2024 17:39:07 +0800 Subject: [PATCH 287/307] add contributors --- CONTRIBUTORS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index a9a42c89..494d5d68 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -45,6 +45,8 @@ Contributors: * [Kevin Sapper](https://github.com/sappo) * [Kyle Chisholm](https://github.com/ChisholmKyle) * [Linus Wallgren](https://github.com/ecksun) +* [Luo Jin](https://github.com/Up-wind) +* [Max](https://github.com/maebex) * [MaxBrandtner](https://github.com/MaxBrandtner) * [Mateusz Szafoni](https://github.com/raiden00pl) * Mike Pontillo @@ -55,6 +57,7 @@ Contributors: * [Moorthy](https://github.com/moorthy-bs) * [myd7349](https://github.com/myd7349) * [NancyLi1013](https://github.com/NancyLi1013) +* [Orri](https://github.com/sbvoxel) * Paulo Antonio Alvarez * [Paweł Malowany](https://github.com/PawelMalowany) * [Pawel Winogrodzki](https://github.com/PawelWMS) From 8a334b014038ef02065fcd41e6096c99102bcc36 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Tue, 26 Dec 2023 09:44:51 +0100 Subject: [PATCH 288/307] Fix indentation (should use spaces) Signed-off-by: DL6ER --- cJSON.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cJSON.c b/cJSON.c index 61483d90..cac1164b 100644 --- a/cJSON.c +++ b/cJSON.c @@ -570,10 +570,10 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out { length = sprintf((char*)number_buffer, "null"); } - else if(d == (double)item->valueint) - { - length = sprintf((char*)number_buffer, "%d", item->valueint); - } + else if(d == (double)item->valueint) + { + length = sprintf((char*)number_buffer, "%d", item->valueint); + } else { /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ From 324973008ced4ea03d1626a00915d0399ecbd9db Mon Sep 17 00:00:00 2001 From: Shaun Case Date: Fri, 29 Mar 2024 10:55:41 -0700 Subject: [PATCH 289/307] Fix spelling errors found by CodeSpell. See https://github.com/codespell-project/codespell --- tests/cjson_add.c | 2 +- tests/print_object.c | 2 +- tests/unity/auto/parse_output.rb | 2 +- tests/unity/docs/UnityGettingStartedGuide.md | 2 +- tests/unity/extras/eclipse/error_parsers.txt | 2 +- tests/unity/src/unity.c | 2 +- tests/unity/test/rakefile | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/cjson_add.c b/tests/cjson_add.c index b02f1e27..ac96ce75 100644 --- a/tests/cjson_add.c +++ b/tests/cjson_add.c @@ -34,7 +34,7 @@ static void * CJSON_CDECL failing_malloc(size_t size) 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) { free(pointer); diff --git a/tests/print_object.c b/tests/print_object.c index 3ed0bfed..507d9759 100644 --- a/tests/print_object.c +++ b/tests/print_object.c @@ -63,7 +63,7 @@ static void assert_print_object(const char * const expected, const char * const formatted_buffer.format = true; 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); } diff --git a/tests/unity/auto/parse_output.rb b/tests/unity/auto/parse_output.rb index f16cdb03..8e88fff0 100644 --- a/tests/unity/auto/parse_output.rb +++ b/tests/unity/auto/parse_output.rb @@ -78,7 +78,7 @@ def test_passed_unity_fixture(array) @array_list.push ' ' 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) last_item = array.length - 1 test_name = array[last_item - 2] diff --git a/tests/unity/docs/UnityGettingStartedGuide.md b/tests/unity/docs/UnityGettingStartedGuide.md index 50fc91c7..08888a12 100644 --- a/tests/unity/docs/UnityGettingStartedGuide.md +++ b/tests/unity/docs/UnityGettingStartedGuide.md @@ -72,7 +72,7 @@ header files. These three files _are_ Unity. into this folder already. This is where all the handy documentation can be found. - `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 want to look here. - `test` - This is how Unity and its scripts are all tested. If you're just using diff --git a/tests/unity/extras/eclipse/error_parsers.txt b/tests/unity/extras/eclipse/error_parsers.txt index 94e34ff3..f7ce8bd0 100644 --- a/tests/unity/extras/eclipse/error_parsers.txt +++ b/tests/unity/extras/eclipse/error_parsers.txt @@ -2,7 +2,7 @@ Eclipse error parsers ===================== 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 to add them manually. diff --git a/tests/unity/src/unity.c b/tests/unity/src/unity.c index d02610a7..eee6f965 100644 --- a/tests/unity/src/unity.c +++ b/tests/unity/src/unity.c @@ -8,7 +8,7 @@ #include "unity.h" #include -/* 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 void UNITY_OUTPUT_CHAR(int); #endif diff --git a/tests/unity/test/rakefile b/tests/unity/test/rakefile index 4a2f3d2c..f05fb7a9 100644 --- a/tests/unity/test/rakefile +++ b/tests/unity/test/rakefile @@ -26,7 +26,7 @@ task :prepare_for_tests => TEMP_DIRS include RakefileHelpers -# Load proper GCC as defult configuration +# Load proper GCC as default configuration DEFAULT_CONFIG_FILE = 'gcc_auto_stdint.yml' configure_toolchain(DEFAULT_CONFIG_FILE) From 424ce4ce9668f288fb4ab665775546d3ed709e96 Mon Sep 17 00:00:00 2001 From: Alanscut Date: Wed, 19 Jun 2024 10:43:55 +0800 Subject: [PATCH 290/307] Revert "feat: add tests for #842" to fix test failures This reverts commit 5b502cdbfb21fbe5f6cf9ffbd2b96e4281a741e6. Related to #860 --- tests/CMakeLists.txt | 1 - tests/misc_tests.c | 18 ------------------ 2 files changed, 19 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9e8962f6..c7592213 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -62,7 +62,6 @@ if(ENABLE_CJSON_TEST) option(ENABLE_VALGRIND OFF "Enable the valgrind memory checker for the tests.") if (ENABLE_VALGRIND) - add_compile_definitions(ENABLE_VALGRIND) find_program(MEMORYCHECK_COMMAND valgrind) if ("${MEMORYCHECK_COMMAND}" MATCHES "MEMORYCHECK_COMMAND-NOTFOUND") message(WARNING "Valgrind couldn't be found.") diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 94dd91aa..ba3e003e 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -732,23 +732,6 @@ static void cjson_set_bool_value_must_not_break_objects(void) 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) { UNITY_BEGIN(); @@ -779,7 +762,6 @@ int CJSON_CDECL main(void) 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_bool_value_must_not_break_objects); - RUN_TEST(deallocated_pointers_should_be_set_to_null); return UNITY_END(); } From f28a468e3b287d633fea5d4d5ab444bb9354b4bc Mon Sep 17 00:00:00 2001 From: Nicolas Badoux Date: Fri, 23 Aug 2024 14:14:10 +0000 Subject: [PATCH 291/307] Check for NULL in cJSON_DetachItemViaPointer --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index cac1164b..483d0c0c 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2204,7 +2204,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * c CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) { - if ((parent == NULL) || (item == NULL)) + if ((parent == NULL) || (parent->child == NULL) || (item == NULL) || (item->prev == NULL)) { return NULL; } From a78d975537a8df40d58a96f8ce326d7fb625e1e5 Mon Sep 17 00:00:00 2001 From: Nicolas Badoux Date: Sun, 25 Aug 2024 23:18:14 +0200 Subject: [PATCH 292/307] cJSON_DetachItemViaPointer: added test and fix for check for null in item->prev --- cJSON.c | 2 +- tests/misc_tests.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 483d0c0c..fe22bd83 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2204,7 +2204,7 @@ CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * c CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) { - if ((parent == NULL) || (parent->child == NULL) || (item == NULL) || (item->prev == NULL)) + if ((parent == NULL) || (item == NULL) || (item != parent->child && item->prev == NULL)) { return NULL; } diff --git a/tests/misc_tests.c b/tests/misc_tests.c index ba3e003e..b9c59e71 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -280,6 +280,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."); } +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) { cJSON replacements[3]; @@ -746,6 +761,7 @@ int CJSON_CDECL main(void) RUN_TEST(cjson_should_not_parse_to_deeply_nested_jsons); 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_return_null_if_item_prev_is_null); RUN_TEST(cjson_replace_item_via_pointer_should_replace_items); RUN_TEST(cjson_replace_item_in_object_should_preserve_name); RUN_TEST(cjson_functions_should_not_crash_with_null_pointers); From d6d5449e1f271556ea8e6ec0f3026ceb0b4a9508 Mon Sep 17 00:00:00 2001 From: Nicolas Badoux Date: Fri, 23 Aug 2024 14:50:30 +0000 Subject: [PATCH 293/307] fix #881, check overlap before calling strcpy in cJSON_SetValuestring --- cJSON.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index fe22bd83..56f65efe 100644 --- a/cJSON.c +++ b/cJSON.c @@ -403,6 +403,8 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) { 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 == 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; } - 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); return object->valuestring; } From b47edc4750301a17bcc72bf20323d2f625a4ae05 Mon Sep 17 00:00:00 2001 From: Nicolas Badoux Date: Sun, 25 Aug 2024 22:32:02 +0200 Subject: [PATCH 294/307] CJSON_SetValuestring: add test for overlapping string --- tests/misc_tests.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index b9c59e71..b10c0a05 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -471,6 +471,19 @@ static void cjson_functions_should_not_crash_with_null_pointers(void) cJSON_Delete(item); } +static void cjson_set_valuestring_should_return_null_if_strings_overlap(void) +{ + cJSON *obj, *obj_dup; + char* str; + + obj = cJSON_Parse("\"fooz\""); + obj_dup = cJSON_Duplicate(obj, 1); + + str = cJSON_SetValuestring(obj_dup, "beeez"); + cJSON_SetValuestring(obj_dup, str); + cJSON_SetValuestring(obj_dup, ++str); +} + static void *CJSON_CDECL failing_realloc(void *pointer, size_t size) { (void)size; @@ -765,6 +778,7 @@ int CJSON_CDECL main(void) RUN_TEST(cjson_replace_item_via_pointer_should_replace_items); RUN_TEST(cjson_replace_item_in_object_should_preserve_name); 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(skip_utf8_bom_should_skip_bom); RUN_TEST(skip_utf8_bom_should_not_skip_bom_if_not_at_beginning); From 4f4d7f70c253927c4d8130771168c9fa7864d2d4 Mon Sep 17 00:00:00 2001 From: Nicolas Badoux Date: Sun, 25 Aug 2024 23:06:21 +0200 Subject: [PATCH 295/307] CJSON_SetValuestring: better test for overlapping string --- tests/misc_tests.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index b10c0a05..e1187f83 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -473,15 +473,19 @@ static void cjson_functions_should_not_crash_with_null_pointers(void) static void cjson_set_valuestring_should_return_null_if_strings_overlap(void) { - cJSON *obj, *obj_dup; + cJSON *obj; char* str; + char* str2; - obj = cJSON_Parse("\"fooz\""); - obj_dup = cJSON_Duplicate(obj, 1); + obj = cJSON_Parse("\"foo0z\""); - str = cJSON_SetValuestring(obj_dup, "beeez"); - cJSON_SetValuestring(obj_dup, str); - cJSON_SetValuestring(obj_dup, ++str); + 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); } static void *CJSON_CDECL failing_realloc(void *pointer, size_t size) From 078c4e6c53f13dff15f0eaac1611abb6379e0206 Mon Sep 17 00:00:00 2001 From: Nicolas Badoux Date: Mon, 26 Aug 2024 09:48:59 +0200 Subject: [PATCH 296/307] Free mem in cjson_set_valuestring_should_return_null_if_strings_overlap --- tests/misc_tests.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/misc_tests.c b/tests/misc_tests.c index e1187f83..606b4603 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -486,6 +486,7 @@ static void cjson_set_valuestring_should_return_null_if_strings_overlap(void) /* 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) From 9d1b229086a7b069fb5f4e3be0226a22480a6707 Mon Sep 17 00:00:00 2001 From: Nicolas Badoux Date: Fri, 30 Aug 2024 13:36:22 +0200 Subject: [PATCH 297/307] Added max recusrion depth for cJSONDuplicate to prevent stack exhaustion in case of circular reference --- cJSON.c | 12 +++++++++++- cJSON.h | 6 ++++++ tests/misc_tests.c | 18 ++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 56f65efe..9399c0dd 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2737,7 +2737,14 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int co } /* 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) +{ + return cJSON_Duplicate_rec(item, 0, recurse ); +} + +cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse) { cJSON *newitem = NULL; cJSON *child = NULL; @@ -2784,7 +2791,10 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) child = item->child; 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, true); /* Duplicate (with recurse) each item in the ->next chain */ if (!newchild) { goto fail; diff --git a/cJSON.h b/cJSON.h index 88cf0bcf..37520bbc 100644 --- a/cJSON.h +++ b/cJSON.h @@ -137,6 +137,12 @@ typedef int cJSON_bool; #define CJSON_NESTING_LIMIT 1000 #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 */ CJSON_PUBLIC(const char*) cJSON_Version(void); diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 606b4603..a96c2fdc 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -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."); } +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) { cJSON number[1] = {{NULL, NULL, NULL, cJSON_Number, NULL, 0, 0, NULL}}; @@ -777,6 +794,7 @@ int CJSON_CDECL main(void) RUN_TEST(cjson_get_object_item_case_sensitive_should_not_crash_with_array); RUN_TEST(typecheck_functions_should_check_type); 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_detach_item_via_pointer_should_detach_items); RUN_TEST(cjson_detach_item_via_pointer_should_return_null_if_item_prev_is_null); From 12c4bf1986c288950a3d06da757109a6aa1ece38 Mon Sep 17 00:00:00 2001 From: Nicolas Badoux Date: Fri, 30 Aug 2024 15:09:28 +0200 Subject: [PATCH 298/307] Wrong counter increment --- cJSON.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON.c b/cJSON.c index 9399c0dd..d7c72363 100644 --- a/cJSON.c +++ b/cJSON.c @@ -2794,7 +2794,7 @@ cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse) if(depth >= CJSON_CIRCULAR_LIMIT) { goto fail; } - newchild = cJSON_Duplicate_rec(child, ++depth, true); /* Duplicate (with recurse) each item in the ->next chain */ + newchild = cJSON_Duplicate_rec(child, depth + 1, true); /* Duplicate (with recurse) each item in the ->next chain */ if (!newchild) { goto fail; From a328d65ad490b64da8c87523cbbfe16050ba5bf6 Mon Sep 17 00:00:00 2001 From: PeterAlfredLee Date: Mon, 21 Apr 2025 15:18:10 +0800 Subject: [PATCH 299/307] allocate memory for the temporary buffer Allocate memory for the temporary buffer when paring numbers. This fixes CVE-2023-26819 --- cJSON.c | 37 ++++++++++++++++++++++++++++++++----- tests/misc_tests.c | 17 +++++++++++++++++ tests/parse_number.c | 20 ++++++++++++++++++++ 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/cJSON.c b/cJSON.c index d7c72363..ca824f0e 100644 --- a/cJSON.c +++ b/cJSON.c @@ -308,9 +308,11 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu { double number = 0; unsigned char *after_end = NULL; - unsigned char number_c_string[64]; + unsigned char *number_c_string; unsigned char decimal_point = get_decimal_point(); size_t i = 0; + size_t number_string_length = 0; + cJSON_bool has_decimal_point = false; if ((input_buffer == NULL) || (input_buffer->content == NULL)) { @@ -320,7 +322,7 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu /* copy the number into a temporary buffer and replace '.' with the decimal point * of the current locale (for strtod) * This also takes care of '\0' not necessarily being available for marking the end of the input */ - for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + for (i = 0; can_access_at_index(input_buffer, i); i++) { switch (buffer_at_offset(input_buffer)[i]) { @@ -338,11 +340,12 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu case '-': case 'e': case 'E': - number_c_string[i] = buffer_at_offset(input_buffer)[i]; + number_string_length++; break; case '.': - number_c_string[i] = decimal_point; + number_string_length++; + has_decimal_point = true; break; default: @@ -350,11 +353,33 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu } } loop_end: - number_c_string[i] = '\0'; + /* malloc for temporary buffer, add 1 for '\0' */ + number_c_string = (unsigned char *) input_buffer->hooks.allocate(number_string_length + 1); + if (number_c_string == NULL) + { + return false; /* allocation failure */ + } + + memcpy(number_c_string, buffer_at_offset(input_buffer), number_string_length); + number_c_string[number_string_length] = '\0'; + + if (has_decimal_point) + { + for (i = 0; i < number_string_length; i++) + { + if (number_c_string[i] == '.') + { + /* replace '.' with the decimal point of the current locale (for strtod) */ + number_c_string[i] = decimal_point; + } + } + } number = strtod((const char*)number_c_string, (char**)&after_end); if (number_c_string == after_end) { + /* free the temporary buffer */ + input_buffer->hooks.deallocate(number_c_string); return false; /* parse_error */ } @@ -377,6 +402,8 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu item->type = cJSON_Number; input_buffer->offset += (size_t)(after_end - number_c_string); + /* free the temporary buffer */ + input_buffer->hooks.deallocate(number_c_string); return true; } diff --git a/tests/misc_tests.c b/tests/misc_tests.c index a96c2fdc..7c616479 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -782,6 +782,22 @@ static void cjson_set_bool_value_must_not_break_objects(void) cJSON_Delete(sobj); } +static void cjson_parse_big_numbers_should_not_report_error(void) +{ + cJSON *valid_big_number_json_object1 = cJSON_Parse("{\"a\": true, \"b\": [ null,9999999999999999999999999999999999999999999999912345678901234567]}"); + cJSON *valid_big_number_json_object2 = cJSON_Parse("{\"a\": true, \"b\": [ null,999999999999999999999999999999999999999999999991234567890.1234567E3]}"); + const char *invalid_big_number_json1 = "{\"a\": true, \"b\": [ null,99999999999999999999999999999999999999999999999.1234567890.1234567]}"; + const char *invalid_big_number_json2 = "{\"a\": true, \"b\": [ null,99999999999999999999999999999999999999999999999E1234567890e1234567]}"; + + TEST_ASSERT_NOT_NULL(valid_big_number_json_object1); + TEST_ASSERT_NOT_NULL(valid_big_number_json_object2); + TEST_ASSERT_NULL_MESSAGE(cJSON_Parse(invalid_big_number_json1), "Invalid big number JSONs should not be parsed."); + TEST_ASSERT_NULL_MESSAGE(cJSON_Parse(invalid_big_number_json2), "Invalid big number JSONs should not be parsed."); + + cJSON_Delete(valid_big_number_json_object1); + cJSON_Delete(valid_big_number_json_object2); +} + int CJSON_CDECL main(void) { UNITY_BEGIN(); @@ -815,6 +831,7 @@ int CJSON_CDECL main(void) 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_bool_value_must_not_break_objects); + RUN_TEST(cjson_parse_big_numbers_should_not_report_error); return UNITY_END(); } diff --git a/tests/parse_number.c b/tests/parse_number.c index 4cb72ec2..defda4ad 100644 --- a/tests/parse_number.c +++ b/tests/parse_number.c @@ -48,6 +48,7 @@ static void assert_parse_number(const char *string, int integer, double real) parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; buffer.content = (const unsigned char*)string; buffer.length = strlen(string) + sizeof(""); + buffer.hooks = global_hooks; TEST_ASSERT_TRUE(parse_number(item, &buffer)); assert_is_number(item); @@ -55,6 +56,17 @@ static void assert_parse_number(const char *string, int integer, double real) TEST_ASSERT_EQUAL_DOUBLE(real, item->valuedouble); } +static void assert_parse_big_number(const char *string) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + buffer.content = (const unsigned char*)string; + buffer.length = strlen(string) + sizeof(""); + buffer.hooks = global_hooks; + + TEST_ASSERT_TRUE(parse_number(item, &buffer)); + assert_is_number(item); +} + static void parse_number_should_parse_zero(void) { assert_parse_number("0", 0, 0); @@ -96,6 +108,13 @@ static void parse_number_should_parse_negative_reals(void) assert_parse_number("-123e-128", 0, -123e-128); } +static void parse_number_should_parse_big_numbers(void) +{ + assert_parse_big_number("9999999999999999999999999999999999999999999999912345678901234567"); + assert_parse_big_number("9999999999999999999999999999999999999999999999912345678901234567E10"); + assert_parse_big_number("999999999999999999999999999999999999999999999991234567890.1234567"); +} + int CJSON_CDECL main(void) { /* initialize cJSON item */ @@ -106,5 +125,6 @@ int CJSON_CDECL main(void) RUN_TEST(parse_number_should_parse_positive_integers); RUN_TEST(parse_number_should_parse_positive_reals); RUN_TEST(parse_number_should_parse_negative_reals); + RUN_TEST(parse_number_should_parse_big_numbers); return UNITY_END(); } From 8f2beb57ddad1f94bed899790b00f46df893ccac Mon Sep 17 00:00:00 2001 From: PeterAlfredLee Date: Mon, 21 Apr 2025 18:14:45 +0800 Subject: [PATCH 300/307] bump version of actions/upload-artifact --- .github/workflows/ci-fuzz.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-fuzz.yml b/.github/workflows/ci-fuzz.yml index 36d89fbd..9e8be0bc 100644 --- a/.github/workflows/ci-fuzz.yml +++ b/.github/workflows/ci-fuzz.yml @@ -16,7 +16,7 @@ jobs: fuzz-seconds: 600 dry-run: false - name: Upload Crash - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v4 if: failure() with: name: artifacts From 74e1ff4994aa4139126967f6d289b675b4b36fef Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 5 Sep 2025 14:53:20 +0800 Subject: [PATCH 301/307] fix the incorrect check in decode_array_index_from_pointer (#957) this fixes CVE-2025-57052 --- cJSON_Utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 63651dfb..8fa24f8e 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -282,7 +282,7 @@ static cJSON_bool decode_array_index_from_pointer(const unsigned char * const po return 0; } - for (position = 0; (pointer[position] >= '0') && (pointer[0] <= '9'); position++) + for (position = 0; (pointer[position] >= '0') && (pointer[position] <= '9'); position++) { parsed_index = (10 * parsed_index) + (size_t)(pointer[position] - '0'); From c859b25da02955fef659d658b8f324b5cde87be3 Mon Sep 17 00:00:00 2001 From: Alan Wang Date: Tue, 9 Sep 2025 21:56:10 +0800 Subject: [PATCH 302/307] Release 1.7.19 (#958) --- CHANGELOG.md | 12 ++++++++++++ CMakeLists.txt | 2 +- CONTRIBUTORS.md | 3 +++ Makefile | 2 +- cJSON.c | 2 +- cJSON.h | 2 +- 6 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de1d8e66..2f046e34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +1.7.19 (Sep 9, 2025) +====== +Fixes: +------ +* Fix indentation (should use spaces), see #814 +* Fix spelling errors found by CodeSpell, see #841 +* Check for NULL in cJSON_DetachItemViaPointer, fixes #882, see #886 +* Fix #881, check overlap before calling strcpy in cJSON_SetValuestring, see #885 +* Fix #880 Max recursion depth for cJSON_Duplicate to prevent stack exhaustion, see #888 +* Allocate memory for the temporary buffer when paring numbers, see #939 +* fix the incorrect check in decode_array_index_from_pointer, see #957 + 1.7.18 (May 13, 2024) ====== Fixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 36a6cb57..c7ca27f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0) cmake_minimum_required(VERSION 3.0) project(cJSON - VERSION 1.7.18 + VERSION 1.7.19 LANGUAGES C) cmake_policy(SET CMP0054 NEW) # set CMP0054 policy diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 494d5d68..b9db178a 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -24,6 +24,7 @@ Contributors: * [Debora Grosse](https://github.com/DeboraG) * [dieyushi](https://github.com/dieyushi) * [Dōngwén Huáng (黄东文)](https://github.com/DongwenHuang) +* [Dominik](https://github.com/DL6ER) * [Donough Liu](https://github.com/ldm0) * [Erez Oxman](https://github.com/erez-o) * Eswar Yaganti @@ -80,6 +81,8 @@ Contributors: * [Stephan Gatzka](https://github.com/gatzka) * [Tony Langhammer](https://github.com/BigBrainAFK) * [Vemake](https://github.com/vemakereporter) +* [vwvw](https://github.com/vwvw) +* [warmsocks](https://github.com/warmsocks) * [Wei Tan](https://github.com/tan-wei) * [Weston Schmidt](https://github.com/schmidtw) * [xiaomianhehe](https://github.com/xiaomianhehe) diff --git a/Makefile b/Makefile index 00ef8073..e2676d2f 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c LDLIBS = -lm -LIBVERSION = 1.7.18 +LIBVERSION = 1.7.19 CJSON_SOVERSION = 1 UTILS_SOVERSION = 1 diff --git a/cJSON.c b/cJSON.c index ca824f0e..6e4fb0dd 100644 --- a/cJSON.c +++ b/cJSON.c @@ -117,7 +117,7 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 18) +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 19) #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif diff --git a/cJSON.h b/cJSON.h index 37520bbc..cab5feb4 100644 --- a/cJSON.h +++ b/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 18 +#define CJSON_VERSION_PATCH 19 #include From a29814f285cc531c00223743ad3c55cd38c0dc56 Mon Sep 17 00:00:00 2001 From: Lee Date: Sat, 7 Feb 2026 17:13:51 +0800 Subject: [PATCH 303/307] upgrade version of cmake_minimum_required (#986) github actions fix --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c7ca27f0..59e4af5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0) -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.5) project(cJSON VERSION 1.7.19 From 5cc0e39f42dfe28cb8541f95fa2c513f0d550210 Mon Sep 17 00:00:00 2001 From: liloler <1258447103@qq.com> Date: Wed, 25 Feb 2026 15:40:05 +0800 Subject: [PATCH 304/307] Fix: add depth check to prevent stack overflow in cJSON_Print (#984) --- cJSON.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cJSON.c b/cJSON.c index 6e4fb0dd..f16a7bcc 100644 --- a/cJSON.c +++ b/cJSON.c @@ -1598,6 +1598,11 @@ static cJSON_bool print_array(const cJSON * const item, printbuffer * const outp return false; } + if (output_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* nesting is too deep */ + } + /* Compose the output array. */ /* opening square bracket */ output_pointer = ensure(output_buffer, 1); @@ -1778,6 +1783,11 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out return false; } + if (output_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* nesting is too deep */ + } + /* Compose the output: */ length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ output_pointer = ensure(output_buffer, length + 1); From a3f3d6c7843f3021b648623d13bc4fbca0084838 Mon Sep 17 00:00:00 2001 From: Lee Date: Thu, 12 Mar 2026 19:18:15 +0800 Subject: [PATCH 305/307] docs: fix outdated CMake version requirement in README (#990) The README stated that CMake 2.8.5+ was required, but CMakeLists.txt requires CMake 3.5+. This inconsistency caused confusion for users with CMake versions between 2.8.5 and 3.5. Also updated library_config/uninstall.cmake to match for consistency. Fixes #988 --- README.md | 2 +- library_config/uninstall.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 99147afd..9c7ed142 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ cJSON is written in ANSI C (C89) in order to support as many platforms and compi #### CMake -With CMake, cJSON supports a full blown build system. This way you get the most features. CMake with an equal or higher version than 2.8.5 is supported. With CMake it is recommended to do an out of tree build, meaning the compiled files are put in a directory separate from the source files. So in order to build cJSON with CMake on a Unix platform, make a `build` directory and run CMake inside it. +With CMake, cJSON supports a full blown build system. This way you get the most features. CMake with an equal or higher version than 3.5 is supported. With CMake it is recommended to do an out of tree build, meaning the compiled files are put in a directory separate from the source files. So in order to build cJSON with CMake on a Unix platform, make a `build` directory and run CMake inside it. ``` mkdir build diff --git a/library_config/uninstall.cmake b/library_config/uninstall.cmake index e751ec47..a4006682 100644 --- a/library_config/uninstall.cmake +++ b/library_config/uninstall.cmake @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.5) +cmake_minimum_required(VERSION 3.5) set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") From b2890c8d76bbb64e710585ebc0a917196b9c67e7 Mon Sep 17 00:00:00 2001 From: Lee Date: Thu, 12 Mar 2026 19:18:36 +0800 Subject: [PATCH 306/307] fix: prevent NULL pointer dereference in cJSON_SetNumberHelper (#991) Add NULL check at the beginning of cJSON_SetNumberHelper to prevent segmentation fault when called with NULL object pointer. The function now returns NAN (Not-a-Number) when object is NULL, consistent with error handling patterns in other cJSON functions. This fixes a Denial of Service vulnerability (CWE-476) where an attacker could crash applications using the cJSON library by triggering this function with a NULL pointer. Changes: - cJSON.c: Add NULL check in cJSON_SetNumberHelper - tests/misc_tests.c: Add test case and math.h include Security: Fixes NULL pointer dereference vulnerability --- cJSON.c | 5 +++++ tests/misc_tests.c | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cJSON.c b/cJSON.c index f16a7bcc..88c2d95b 100644 --- a/cJSON.c +++ b/cJSON.c @@ -410,6 +410,11 @@ static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_bu /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) { + if (object == NULL) + { + return (double)NAN; + } + if (number >= INT_MAX) { object->valueint = INT_MAX; diff --git a/tests/misc_tests.c b/tests/misc_tests.c index 7c616479..fe2325e9 100644 --- a/tests/misc_tests.c +++ b/tests/misc_tests.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "unity/examples/unity_config.h" #include "unity/src/unity.h" @@ -478,8 +479,8 @@ static void cjson_functions_should_not_crash_with_null_pointers(void) TEST_ASSERT_NULL(cJSON_SetValuestring(corruptedString, "test")); TEST_ASSERT_NULL(cJSON_SetValuestring(item, NULL)); cJSON_Minify(NULL); - /* skipped because it is only used via a macro that checks for NULL */ - /* cJSON_SetNumberHelper(NULL, 0); */ + /* cJSON_SetNumberHelper should handle NULL gracefully */ + TEST_ASSERT_TRUE(isnan(cJSON_SetNumberHelper(NULL, 0))); /* restore corrupted item2 to delete it */ item2->prev = originalPrev; From fb16e5cf358798aabb049655975cde8427101056 Mon Sep 17 00:00:00 2001 From: Ssh1y Ripple <62094604+Ssh1y@users.noreply.github.com> Date: Thu, 9 Apr 2026 09:59:11 +0800 Subject: [PATCH 307/307] Fix: Type Confusion vulnerability in cJSON_Utils caused by missing type check (#1006) --- cJSON_Utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 8fa24f8e..8b38eb25 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -906,7 +906,7 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_ if ((opcode == MOVE) || (opcode == COPY)) { cJSON *from = get_object_item(patch, "from", case_sensitive); - if (from == NULL) + if (!cJSON_IsString(from)) { /* missing "from" for copy/move. */ status = 4;