From dd040ba44605da3d186e76add85926423b588a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= Date: Mon, 18 May 2020 11:38:36 +0200 Subject: [PATCH 01/94] tests: Fix test_double_serializer without thread-local storage. --- tests/test_double_serializer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_double_serializer.c b/tests/test_double_serializer.c index 71ec8ec..8b2487a 100644 --- a/tests/test_double_serializer.c +++ b/tests/test_double_serializer.c @@ -59,6 +59,7 @@ int main() #else // Just fake it up, so the output matches. printf("obj.to_string(with thread format)=%s\n", "T0.52X"); + printf("obj.to_string(long thread format)=%s\n", "Ttttttttttttt0.52xxxxxxxxxxxxxxxxxxX"); printf("obj.to_string(back to global format)=%s\n", "x0.524y"); #endif if (json_c_set_serialization_double_format(NULL, JSON_C_OPTION_GLOBAL) < 0) From 78642dcb9b9b58bd0111ffba5e46b9346b8d486b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= Date: Mon, 18 May 2020 11:38:58 +0200 Subject: [PATCH 02/94] CMake: Add an option to disable the use of thread-local storage. Using thread-local storage may not be desired in all environments and/or use-cases, thus there should be an option to disable its use on purpose. Fixes #451. --- CMakeLists.txt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 254d324..180d6e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,7 @@ option(ENABLE_RDRAND "Enable RDRAND Hardware RNG Hash Seed" option(ENABLE_THREADING "Enable partial threading support." OFF) option(DISABLE_WERROR "Avoid treating compiler warnings as fatal errors" OFF) option(DISABLE_BSYMBOLIC "Avoid linking with -Bsymbolic-function" OFF) +option(DISABLE_THREAD_LOCAL_STORAGE "Disable Thread-Local Storage (HAVE___THREAD)" OFF) if (UNIX OR MINGW OR CYGWIN) list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) @@ -217,14 +218,16 @@ check_c_source_compiles( "int main() { int i, x = 0; i = __sync_add_and_fetch(&x,1); return x; }" HAVE_ATOMIC_BUILTINS) -check_c_source_compiles( - "__thread int x = 0; int main() { return 0; }" - HAVE___THREAD) +if (NOT DISABLE_THREAD_LOCAL_STORAGE) + check_c_source_compiles( + "__thread int x = 0; int main() { return 0; }" + HAVE___THREAD) -if (HAVE___THREAD) - set(SPEC___THREAD __thread) -elseif (MSVC) - set(SPEC___THREAD __declspec(thread)) + if (HAVE___THREAD) + set(SPEC___THREAD __thread) + elseif (MSVC) + set(SPEC___THREAD __declspec(thread)) + endif() endif() # Hardware random number is not available on Windows? Says, config.h.win32. Best to preserve compatibility. From 76dd99abb24780d1f2a770d2534829aa76798492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= Date: Mon, 18 May 2020 12:26:47 +0200 Subject: [PATCH 03/94] CMake: Re-format config-option block and re-order it alphabetically. --- CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 180d6e9..901eb6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,11 +83,11 @@ COMMAND make package_source ) # Enable or disable features. By default, all features are turned off. -option(ENABLE_RDRAND "Enable RDRAND Hardware RNG Hash Seed" OFF) -option(ENABLE_THREADING "Enable partial threading support." OFF) -option(DISABLE_WERROR "Avoid treating compiler warnings as fatal errors" OFF) -option(DISABLE_BSYMBOLIC "Avoid linking with -Bsymbolic-function" OFF) -option(DISABLE_THREAD_LOCAL_STORAGE "Disable Thread-Local Storage (HAVE___THREAD)" OFF) +option(DISABLE_BSYMBOLIC "Avoid linking with -Bsymbolic-function." OFF) +option(DISABLE_THREAD_LOCAL_STORAGE "Disable using Thread-Local Storage (HAVE___THREAD)." OFF) +option(DISABLE_WERROR "Avoid treating compiler warnings as fatal errors." OFF) +option(ENABLE_RDRAND "Enable RDRAND Hardware RNG Hash Seed." OFF) +option(ENABLE_THREADING "Enable partial threading support." OFF) if (UNIX OR MINGW OR CYGWIN) list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) From a85d2395fff0c806fe86f0446fb9ff1bbf2cb8e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= Date: Mon, 18 May 2020 12:39:38 +0200 Subject: [PATCH 04/94] README: Update configuration options for CMake. --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index f5a7ee3..5cabd9d 100644 --- a/README.md +++ b/README.md @@ -93,16 +93,17 @@ CMake Options The json-c library is built with [CMake](https://cmake.org/cmake-tutorial/), which can take a few options. -Variable | Type | Description ----------------------|--------|-------------- -CMAKE_INSTALL_PREFIX | String | The install location. -CMAKE_BUILD_TYPE | String | Defaults to "debug" -BUILD_SHARED_LIBS | Bool | The default build generates a dynamic (dll/so) library. Set this to OFF to create a static library only. -BUILD_STATIC_LIBS | Bool | The default build generates a static (lib/a) library. Set this to OFF to create a shared library only. -ENABLE_RDRAND | Bool | Enable RDRAND Hardware RNG Hash Seed -ENABLE_THREADING | Bool | Enable partial threading support -DISABLE_WERROR | Bool | Disable use of -Werror -DISABLE_BSYMBOLIC | Bool | Disable use of -Bsymbolic-functions +Variable | Type | Description +-----------------------------|--------|-------------- +CMAKE_INSTALL_PREFIX | String | The install location. +CMAKE_BUILD_TYPE | String | Defaults to "debug". +BUILD_SHARED_LIBS | Bool | The default build generates a dynamic (dll/so) library. Set this to OFF to create a static library only. +BUILD_STATIC_LIBS | Bool | The default build generates a static (lib/a) library. Set this to OFF to create a shared library only. +DISABLE_BSYMBOLIC | Bool | Disable use of -Bsymbolic-functions. +DISABLE_THREAD_LOCAL_STORAGE | Bool | Disable use of Thread-Local Storage (HAVE___THREAD). +DISABLE_WERROR | Bool | Disable use of -Werror. +ENABLE_RDRAND | Bool | Enable RDRAND Hardware RNG Hash Seed. +ENABLE_THREADING | Bool | Enable partial threading support. Pass these options as `-D` on CMake's command-line. From 3008401b2a8f5b25bf5665cafa22b335d9ffdb3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= Date: Mon, 18 May 2020 17:00:17 +0200 Subject: [PATCH 05/94] test_deep_copy: Fix assertion value. --- tests/test_deep_copy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_deep_copy.c b/tests/test_deep_copy.c index b6c1b99..34ef1fe 100644 --- a/tests/test_deep_copy.c +++ b/tests/test_deep_copy.c @@ -126,7 +126,7 @@ int main(int argc, char **argv) src3 = json_tokener_parse(json_str3); assert(src1 != NULL); - assert(src1 != NULL); + assert(src2 != NULL); assert(src3 != NULL); printf("PASSED - loaded input data\n"); From 8f3592b3d59874b4dd230a741fad3ffa99223a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= Date: Mon, 18 May 2020 18:20:01 +0200 Subject: [PATCH 06/94] CMake: Fix out-of-tree build for Doxygen documentation. --- CMakeLists.txt | 11 ++++++----- Doxyfile => Doxyfile.in | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) rename Doxyfile => Doxyfile.in (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 901eb6e..f58301c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -368,12 +368,13 @@ option(BUILD_DOCUMENTATION "Create and install the HTML based API documentation( if (DOXYGEN_FOUND) - add_custom_target(doc - COMMAND ${DOXYGEN_EXECUTABLE} ${PROJECT_SOURCE_DIR}/Doxyfile - WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) + configure_file(${PROJECT_SOURCE_DIR}/Doxyfile.in + ${PROJECT_BINARY_DIR}/Doxyfile) + message(STATUS "Written ${PROJECT_BINARY_DIR}/Doxyfile") - # request to configure the file - configure_file(Doxyfile Doxyfile) + add_custom_target(doc + COMMAND ${DOXYGEN_EXECUTABLE} ${PROJECT_BINARY_DIR}/Doxyfile + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) else (DOXYGEN_FOUND) message("Warning: doxygen not found, the 'doc' target will not be included") diff --git a/Doxyfile b/Doxyfile.in similarity index 99% rename from Doxyfile rename to Doxyfile.in index 06d54e6..42a0853 100644 --- a/Doxyfile +++ b/Doxyfile.in @@ -38,7 +38,7 @@ PROJECT_NAME = json-c # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.14.99 +PROJECT_NUMBER = @PROJECT_VERSION@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -753,7 +753,7 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = +INPUT = @CMAKE_SOURCE_DIR@ @CMAKE_BINARY_DIR@ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses From fa6a7dccb926b1bdb65be74733389a1fbcf9734e Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 18 May 2020 17:31:22 +0000 Subject: [PATCH 07/94] With the change in cc80203, Doxyfile no longer needs to be updated for a release. --- RELEASE_CHECKLIST.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index 94f5307..9ad708c 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -52,7 +52,6 @@ Make any fixes/changes *before* branching. Using ${release}: Update the version in json_c_version.h - Update the version in Doxyfile (PROJECT_NUMBER) Update the version in CMakeLists.txt (VERSION in the project(...) line) Update the version in config.h.win32 (several places) @@ -114,7 +113,6 @@ Add new section to ChangeLog for ${release}+1 Use ${release}.99 to indicate a version "newer" than anything on the branch: Update the version in json_c_version.h - Update the version in Doxyfile Update the version in CMakeLists.txt Update the version in config.h.win32 From 61e2bae5111b49a788fe4c236b473dc86250a7fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= Date: Mon, 18 May 2020 20:32:35 +0200 Subject: [PATCH 08/94] doc: Move Doxyfile into doc subdir --- .gitignore | 2 +- CMakeLists.txt | 19 +------------------ doc/CMakeLists.txt | 16 ++++++++++++++++ Doxyfile.in => doc/Doxyfile.in | 2 +- 4 files changed, 19 insertions(+), 20 deletions(-) create mode 100644 doc/CMakeLists.txt rename Doxyfile.in => doc/Doxyfile.in (99%) diff --git a/.gitignore b/.gitignore index 958ace3..1cdaf9b 100644 --- a/.gitignore +++ b/.gitignore @@ -83,7 +83,7 @@ /Testing/ # ...and build artifacts. -/doc +/doc/html /libjson-c.a /libjson-c.so /libjson-c.so.* diff --git a/CMakeLists.txt b/CMakeLists.txt index f58301c..ec17697 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -361,24 +361,7 @@ set(JSON_C_SOURCES include_directories(${PROJECT_SOURCE_DIR}) include_directories(${PROJECT_BINARY_DIR}) -# generate doxygen documentation for json-c API - -find_package(Doxygen) -option(BUILD_DOCUMENTATION "Create and install the HTML based API documentation(requires Doxygen)" ${DOXYGEN_FOUND}) - -if (DOXYGEN_FOUND) - - configure_file(${PROJECT_SOURCE_DIR}/Doxyfile.in - ${PROJECT_BINARY_DIR}/Doxyfile) - message(STATUS "Written ${PROJECT_BINARY_DIR}/Doxyfile") - - add_custom_target(doc - COMMAND ${DOXYGEN_EXECUTABLE} ${PROJECT_BINARY_DIR}/Doxyfile - WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) - -else (DOXYGEN_FOUND) - message("Warning: doxygen not found, the 'doc' target will not be included") -endif(DOXYGEN_FOUND) +add_subdirectory(doc) # uninstall add_custom_target(uninstall diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 0000000..4872d8e --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,16 @@ +# generate doxygen documentation for json-c API + +find_package(Doxygen) + +if (DOXYGEN_FOUND) + + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in + ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + message(STATUS "Wrote ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile") + + add_custom_target(doc + COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + +else (DOXYGEN_FOUND) + message("Warning: doxygen not found, the 'doc' target will not be included") +endif(DOXYGEN_FOUND) diff --git a/Doxyfile.in b/doc/Doxyfile.in similarity index 99% rename from Doxyfile.in rename to doc/Doxyfile.in index 42a0853..ce8d8ff 100644 --- a/Doxyfile.in +++ b/doc/Doxyfile.in @@ -58,7 +58,7 @@ PROJECT_LOGO = # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = doc +OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and From 1e94da779a9aa107690e4f2921ab4d0300aca579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Esser?= Date: Mon, 18 May 2020 20:36:05 +0200 Subject: [PATCH 09/94] CMake: Fix grammar: written -> wrote. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec17697..333513c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -237,9 +237,9 @@ endif() # Once we've done basic symbol/header searches let's add them in. configure_file(${PROJECT_SOURCE_DIR}/cmake/config.h.in ${PROJECT_BINARY_DIR}/config.h) -message(STATUS "Written ${PROJECT_BINARY_DIR}/config.h") +message(STATUS "Wrote ${PROJECT_BINARY_DIR}/config.h") configure_file(${PROJECT_SOURCE_DIR}/cmake/json_config.h.in ${PROJECT_BINARY_DIR}/json_config.h) -message(STATUS "Written ${PROJECT_BINARY_DIR}/json_config.h") +message(STATUS "Wrote ${PROJECT_BINARY_DIR}/json_config.h") if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections") From 4a546e7b2f471157c6f479df1ef687864fcbd89e Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 24 May 2020 03:53:32 +0000 Subject: [PATCH 10/94] In arraylist, use malloc instead of calloc, avoid clearing with memeset until we really need to, and micro-optimize array_list_add(). --- arraylist.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/arraylist.c b/arraylist.c index e5524ac..3e7bfa8 100644 --- a/arraylist.c +++ b/arraylist.c @@ -40,13 +40,13 @@ struct array_list *array_list_new(array_list_free_fn *free_fn) { struct array_list *arr; - arr = (struct array_list *)calloc(1, sizeof(struct array_list)); + arr = (struct array_list *)malloc(sizeof(struct array_list)); if (!arr) return NULL; arr->size = ARRAY_LIST_DEFAULT_SIZE; arr->length = 0; arr->free_fn = free_fn; - if (!(arr->array = (void **)calloc(arr->size, sizeof(void *)))) + if (!(arr->array = (void **)malloc(arr->size * sizeof(void *)))) { free(arr); return NULL; @@ -92,11 +92,11 @@ static int array_list_expand_internal(struct array_list *arr, size_t max) if (!(t = realloc(arr->array, new_size * sizeof(void *)))) return -1; arr->array = (void **)t; - (void)memset(arr->array + arr->size, 0, (new_size - arr->size) * sizeof(void *)); arr->size = new_size; return 0; } +//static inline int _array_list_put_idx(struct array_list *arr, size_t idx, void *data) int array_list_put_idx(struct array_list *arr, size_t idx, void *data) { if (idx > SIZE_T_MAX - 1) @@ -106,6 +106,17 @@ int array_list_put_idx(struct array_list *arr, size_t idx, void *data) if (idx < arr->length && arr->array[idx]) arr->free_fn(arr->array[idx]); arr->array[idx] = data; + if (idx > arr->length) + { + /* Zero out the arraylist slots in between the old length + and the newly added entry so we know those entries are + empty. + e.g. when setting array[7] in an array that used to be + only 5 elements longs, array[5] and array[6] need to be + set to 0. + */ + memset(arr->array + arr->length, 0, (idx - arr->length) * sizeof(void *)); + } if (arr->length <= idx) arr->length = idx + 1; return 0; @@ -113,7 +124,17 @@ int array_list_put_idx(struct array_list *arr, size_t idx, void *data) int array_list_add(struct array_list *arr, void *data) { - return array_list_put_idx(arr, arr->length, data); + /* Repeat some of array_list_put_idx() so we can skip several + checks that we know are unnecessary when appending at the end + */ + size_t idx = arr->length; + if (idx > SIZE_T_MAX - 1) + return -1; + if (array_list_expand_internal(arr, idx + 1)) + return -1; + arr->array[idx] = data; + arr->length++; + return 0; } void array_list_sort(struct array_list *arr, int (*compar)(const void *, const void *)) From 853b4b5dee4ca26a58f0b71944fa725c4a45ff0a Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 25 May 2020 03:14:06 +0000 Subject: [PATCH 11/94] Start splitting struct json_object into multiple sub-types, as descibed at https://github.com/json-c/json-c/wiki/Proposal:-struct-json_object-split The current changes split out _only_ json_type_object, and thus have a number of hacks to allow the code to continue to build and work. Originally mentioned in issue #535. When complete, this will probably invalidate #552. This is likely to cause notable conflicts in any other significant un-merged changes, such as PR#620. --- README.json_object-split.md | 15 ++ json_object.c | 384 +++++++++++++++++++++++++++++++----- json_object.h | 3 +- json_object_private.h | 53 ++++- tests/CMakeLists.txt | 3 +- 5 files changed, 406 insertions(+), 52 deletions(-) create mode 100644 README.json_object-split.md diff --git a/README.json_object-split.md b/README.json_object-split.md new file mode 100644 index 0000000..f0d8632 --- /dev/null +++ b/README.json_object-split.md @@ -0,0 +1,15 @@ + +This branch implements the changes briefly described at: + +https://github.com/json-c/json-c/wiki/Proposal:-struct-json_object-split + +These were originally mentioned in: +Issue #535 - short string optimization: excessive array length + +The changes are expected to impact and possibly invalidate: +Issue #552 - Some anlysis about memory allocator in json-c + +and will likely cause notable conflicts in any other significant un-merged +changes, such as PR#620 - Introduce json_object_new_string_{ext,noalloc}() + + diff --git a/json_object.c b/json_object.c index c2463c1..1219334 100644 --- a/json_object.c +++ b/json_object.c @@ -45,8 +45,64 @@ const char *json_number_chars = "0123456789.+-eE"; const char *json_hex_chars = "0123456789abcdefABCDEF"; static void json_object_generic_delete(struct json_object *jso); +static void Xjson_object_generic_delete(struct json_object_base *jso); static struct json_object *json_object_new(enum json_type o_type); +// XAX kill this once json_object_base is renamed back to json_object +static inline struct json_object *PUBLIC(struct json_object_base *jso) +{ + return (struct json_object *)jso; +} +static inline const struct json_object *PUBLIC_C(const struct json_object_base *jso) +{ + return (const struct json_object *)jso; +} + +/* + * Helper functions to more safely cast to a particular type of json_object + */ +static inline struct json_object_object *JC_OBJECT(struct json_object_base *jso) +{ + return (void *)jso; +} +static inline const struct json_object_object *JC_OBJECT_C(const struct json_object_base *jso) +{ + return (const void *)jso; +} +static inline struct json_object_array *JC_ARRAY(struct json_object_base *jso) +{ + return (void *)jso; +} +static inline struct json_object_boolean *JC_BOOL(struct json_object_base *jso) +{ + return (void *)jso; +} +static inline struct json_object_double *JC_DOUBLE(struct json_object_base *jso) +{ + return (void *)jso; +} +static inline struct json_object_int *JC_INT(struct json_object_base *jso) +{ + return (void *)jso; +} +static inline struct json_object_string *JC_STRING(struct json_object_base *jso) +{ + return (void *)jso; +} + +#define JC_CONCAT(a,b) a##b +#define JC_CONCAT3(a,b,c) a##b##c + +#define JSON_OBJECT_NEW(jtype, delete_fn) \ + Xjson_object_new(JC_CONCAT(json_type_,jtype), \ + sizeof(struct JC_CONCAT(json_object_,jtype)), \ + &JC_CONCAT3(json_object_,jtype,_to_json_string), \ + (void *)delete_fn) // XAX drop cast +static inline struct json_object_base *Xjson_object_new(enum json_type o_type, + size_t alloc_size, + json_object_to_json_string_fn *to_json_string, + json_object_private_delete_fn *delete_fn); + static json_object_to_json_string_fn json_object_object_to_json_string; static json_object_to_json_string_fn json_object_boolean_to_json_string; static json_object_to_json_string_fn json_object_double_to_json_string_default; @@ -111,10 +167,14 @@ static void json_object_fini(void) /* helper for accessing the optimized string data component in json_object */ +// XAX drop this function static const char *get_string_component(const struct json_object *jso) { + if (jso->newold) + return ((const struct json_object_string *)jso)->data; return (jso->o.c_string.len < LEN_DIRECT_STRING_DATA) ? jso->o.c_string.str.data - : jso->o.c_string.str.ptr; + : jso->o.c_string.str.ptr; + } /* string escaping */ @@ -204,10 +264,42 @@ struct json_object *json_object_get(struct json_object *jso) return jso; } +// XAX remove this Xjson_object_put function once conversion is done +static int Xjson_object_put(struct json_object_base *jso) +{ + if (!jso) + return 0; + + /* Avoid invalid free and crash explicitly instead of (silently) + * segfaulting. + */ + assert(jso->_ref_count > 0); + +#if defined(HAVE_ATOMIC_BUILTINS) && defined(ENABLE_THREADING) + /* Note: this only allow the refcount to remain correct + * when multiple threads are adjusting it. It is still an error + * for a thread to decrement the refcount if it doesn't "own" it, + * as that can result in the thread that loses the race to 0 + * operating on an already-freed object. + */ + if (__sync_sub_and_fetch(&jso->_ref_count, 1) > 0) + return 0; +#else + if (--jso->_ref_count > 0) + return 0; +#endif + + if (jso->_user_delete) + jso->_user_delete(PUBLIC(jso), jso->_userdata); + jso->_delete(PUBLIC(jso)); + return 1; +} int json_object_put(struct json_object *jso) { if (!jso) return 0; + if (jso->newold) + return Xjson_object_put((struct json_object_base *)jso); /* Avoid invalid free and crash explicitly instead of (silently) * segfaulting. @@ -234,9 +326,14 @@ int json_object_put(struct json_object *jso) return 1; } + /* generic object construction and destruction parts */ static void json_object_generic_delete(struct json_object *jso) +{ + Xjson_object_generic_delete((void *)jso); +} +static void Xjson_object_generic_delete(struct json_object_base *jso) { #ifdef REFCOUNT_DEBUG MC_DEBUG("json_object_delete_%s: %p\n", json_type_to_name(jso->o_type), jso); @@ -246,7 +343,8 @@ static void json_object_generic_delete(struct json_object *jso) free(jso); } -static struct json_object *json_object_new(enum json_type o_type) +// XAX remove this once all is using new api +static inline struct json_object *json_object_new(enum json_type o_type) { struct json_object *jso; @@ -256,6 +354,35 @@ static struct json_object *json_object_new(enum json_type o_type) jso->o_type = o_type; jso->_ref_count = 1; jso->_delete = &json_object_generic_delete; + +#ifdef REFCOUNT_DEBUG + lh_table_insert(json_object_table, jso, jso); + MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso); +#endif /* REFCOUNT_DEBUG */ + return jso; +} + +static inline struct json_object_base *Xjson_object_new(enum json_type o_type, + size_t alloc_size, + json_object_to_json_string_fn *to_json_string, + json_object_private_delete_fn *delete_fn) +{ + struct json_object_base *jso; + + jso = (struct json_object_base *)malloc(alloc_size); + if (!jso) + return NULL; + + jso->newold = 1; // XAX cut this after conversion + jso->o_type = o_type; + jso->_ref_count = 1; + jso->_delete = delete_fn; + jso->_to_json_string = to_json_string; + jso->_pb = NULL; + jso->_user_delete = NULL; + jso->_userdata= NULL; + //jso->... // Type-specific fields must be set by caller + #ifdef REFCOUNT_DEBUG lh_table_insert(json_object_table, jso, jso); MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso); @@ -267,24 +394,30 @@ static struct json_object *json_object_new(enum json_type o_type) int json_object_is_type(const struct json_object *jso, enum json_type type) { +#define jso ((const struct json_object_base *)jso) if (!jso) return (type == json_type_null); return (jso->o_type == type); +#undef jso } enum json_type json_object_get_type(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) if (!jso) return json_type_null; return jso->o_type; +#undef jso } void *json_object_get_userdata(json_object *jso) { +#define jso ((const struct json_object_base *)jso) return jso ? jso->_userdata : NULL; +#undef jso } -void json_object_set_userdata(json_object *jso, void *userdata, json_object_delete_fn *user_delete) +static void Xjson_object_set_userdata(json_object *jso, void *userdata, json_object_delete_fn *user_delete) { // Can't return failure, so abort if we can't perform the operation. assert(jso != NULL); @@ -296,10 +429,30 @@ void json_object_set_userdata(json_object *jso, void *userdata, json_object_dele jso->_userdata = userdata; jso->_user_delete = user_delete; } +void json_object_set_userdata(json_object *jso, void *userdata, json_object_delete_fn *user_delete) +{ + // XAX call old code: + if (!jso->newold) + { + Xjson_object_set_userdata(jso, userdata, user_delete); + return; + } +#define jso ((struct json_object_base *)jso) + // Can't return failure, so abort if we can't perform the operation. + assert(jso != NULL); + + // First, clean up any previously existing user info + if (jso->_user_delete) + jso->_user_delete(PUBLIC(jso), jso->_userdata); + + jso->_userdata = userdata; + jso->_user_delete = user_delete; +#undef jso +} /* set a custom conversion to string */ -void json_object_set_serializer(json_object *jso, json_object_to_json_string_fn *to_string_func, +static void Xjson_object_set_serializer(json_object *jso, json_object_to_json_string_fn *to_string_func, void *userdata, json_object_delete_fn *user_delete) { json_object_set_userdata(jso, userdata, user_delete); @@ -333,10 +486,53 @@ void json_object_set_serializer(json_object *jso, json_object_to_json_string_fn jso->_to_json_string = to_string_func; } +void json_object_set_serializer(json_object *jso, json_object_to_json_string_fn *to_string_func, + void *userdata, json_object_delete_fn *user_delete) +{ + // XAX call old code, remove after conversion: + if (jso && !jso->newold) + { + Xjson_object_set_serializer(jso, to_string_func, userdata, user_delete); + return; + } +#define jso ((struct json_object_base *)jso) + json_object_set_userdata(PUBLIC(jso), userdata, user_delete); + + if (to_string_func == NULL) + { + // Reset to the standard serialization function + switch (jso->o_type) + { + case json_type_null: jso->_to_json_string = NULL; break; + case json_type_boolean: + jso->_to_json_string = &json_object_boolean_to_json_string; + break; + case json_type_double: + jso->_to_json_string = &json_object_double_to_json_string_default; + break; + case json_type_int: jso->_to_json_string = &json_object_int_to_json_string; break; + case json_type_object: + jso->_to_json_string = &json_object_object_to_json_string; + break; + case json_type_array: + jso->_to_json_string = &json_object_array_to_json_string; + break; + case json_type_string: + jso->_to_json_string = &json_object_string_to_json_string; + break; + } + return; + } + + jso->_to_json_string = to_string_func; +#undef jso +} + /* extended conversion to string */ const char *json_object_to_json_string_length(struct json_object *jso, int flags, size_t *length) { +#define jso ((struct json_object_base *)jso) const char *r = NULL; size_t s = 0; @@ -349,7 +545,7 @@ const char *json_object_to_json_string_length(struct json_object *jso, int flags { printbuf_reset(jso->_pb); - if (jso->_to_json_string(jso, jso->_pb, 0, flags) >= 0) + if (jso->_to_json_string(PUBLIC(jso), jso->_pb, 0, flags) >= 0) { s = (size_t)jso->_pb->bpos; r = jso->_pb->buf; @@ -359,6 +555,7 @@ const char *json_object_to_json_string_length(struct json_object *jso, int flags if (length) *length = s; return r; +#undef jso } const char *json_object_to_json_string_ext(struct json_object *jso, int flags) @@ -393,6 +590,7 @@ static void indent(struct printbuf *pb, int level, int flags) static int json_object_object_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { +#define jso ((struct json_object_base *)jso) int had_children = 0; struct json_object_iter iter; @@ -432,6 +630,7 @@ static int json_object_object_to_json_string(struct json_object *jso, struct pri return printbuf_strappend(pb, /*{*/ " }"); else return printbuf_strappend(pb, /*{*/ "}"); +#undef jso } static void json_object_lh_entry_free(struct lh_entry *ent) @@ -441,57 +640,62 @@ static void json_object_lh_entry_free(struct lh_entry *ent) json_object_put((struct json_object *)lh_entry_v(ent)); } -static void json_object_object_delete(struct json_object *jso) +static void json_object_object_delete(struct json_object_base *jso_base) { - lh_table_free(jso->o.c_object); - json_object_generic_delete(jso); + struct json_object_object *jso = (struct json_object_object *)jso_base; + lh_table_free(jso->c_object); + Xjson_object_generic_delete(jso_base); } struct json_object *json_object_new_object(void) { - struct json_object *jso = json_object_new(json_type_object); - if (!jso) + struct json_object_base *jso_base; + jso_base = JSON_OBJECT_NEW(object, &json_object_object_delete); + if (!jso_base) return NULL; - jso->_delete = &json_object_object_delete; - jso->_to_json_string = &json_object_object_to_json_string; - jso->o.c_object = + struct json_object_object *jso = (struct json_object_object *)jso_base; + jso->c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, &json_object_lh_entry_free); - if (!jso->o.c_object) + if (!jso->c_object) { - json_object_generic_delete(jso); + Xjson_object_generic_delete(jso_base); errno = ENOMEM; return NULL; } - return jso; + return PUBLIC(jso_base); } struct lh_table *json_object_get_object(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) if (!jso) return NULL; switch (jso->o_type) { - case json_type_object: return jso->o.c_object; + case json_type_object: return JC_OBJECT_C(jso)->c_object; default: return NULL; } +#undef jso } int json_object_object_add_ex(struct json_object *jso, const char *const key, struct json_object *const val, const unsigned opts) { +#define jso ((struct json_object_base *)jso) +#define val ((struct json_object_base *)val) struct json_object *existing_value = NULL; struct lh_entry *existing_entry; unsigned long hash; - assert(json_object_get_type(jso) == json_type_object); + assert(json_object_get_type(PUBLIC(jso)) == json_type_object); // We lookup the entry and replace the value, rather than just deleting // and re-adding it, so the existing key remains valid. - hash = lh_get_hash(jso->o.c_object, (const void *)key); + hash = lh_get_hash(JC_OBJECT(jso)->c_object, (const void *)key); existing_entry = (opts & JSON_C_OBJECT_ADD_KEY_IS_NEW) ? NULL - : lh_table_lookup_entry_w_hash(jso->o.c_object, (const void *)key, hash); + : lh_table_lookup_entry_w_hash(JC_OBJECT(jso)->c_object, (const void *)key, hash); // The caller must avoid creating loops in the object tree, but do a // quick check anyway to make sure we're not creating a trivial loop. @@ -504,13 +708,15 @@ int json_object_object_add_ex(struct json_object *jso, const char *const key, (opts & JSON_C_OBJECT_KEY_IS_CONSTANT) ? (const void *)key : strdup(key); if (k == NULL) return -1; - return lh_table_insert_w_hash(jso->o.c_object, k, val, hash, opts); + return lh_table_insert_w_hash(JC_OBJECT(jso)->c_object, k, val, hash, opts); } existing_value = (json_object *)lh_entry_v(existing_entry); if (existing_value) json_object_put(existing_value); existing_entry->v = val; return 0; +#undef jso +#undef val } int json_object_object_add(struct json_object *jso, const char *key, struct json_object *val) @@ -520,10 +726,13 @@ int json_object_object_add(struct json_object *jso, const char *key, struct json int json_object_object_length(const struct json_object *jso) { - assert(json_object_get_type(jso) == json_type_object); - return lh_table_length(jso->o.c_object); +#define jso ((const struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_object); + return lh_table_length(JC_OBJECT_C(jso)->c_object); +#undef jso } + size_t json_c_object_sizeof(void) { return sizeof(struct json_object); @@ -539,6 +748,7 @@ struct json_object *json_object_object_get(const struct json_object *jso, const json_bool json_object_object_get_ex(const struct json_object *jso, const char *key, struct json_object **value) { +#define jso ((const struct json_object_base *)jso) if (value != NULL) *value = NULL; @@ -548,20 +758,24 @@ json_bool json_object_object_get_ex(const struct json_object *jso, const char *k switch (jso->o_type) { case json_type_object: - return lh_table_lookup_ex(jso->o.c_object, (const void *)key, (void **)value); + return lh_table_lookup_ex(JC_OBJECT_C(jso)->c_object, (const void *)key, (void **)value); default: if (value != NULL) *value = NULL; return 0; } +#undef jso } void json_object_object_del(struct json_object *jso, const char *key) { - assert(json_object_get_type(jso) == json_type_object); - lh_table_delete(jso->o.c_object, key); +#define jso ((struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC(jso)) == json_type_object); + lh_table_delete(JC_OBJECT(jso)->c_object, key); +#undef jso } +// XAX ------------------------------ start unconverted code: /* json_object_boolean */ static int json_object_boolean_to_json_string(struct json_object *jso, struct printbuf *pb, @@ -1398,17 +1612,18 @@ struct json_object *json_object_new_null(void) return NULL; } -static int json_object_all_values_equal(struct json_object *jso1, struct json_object *jso2) +static int json_object_all_values_equal(struct json_object_base *jso1, struct json_object_base *jso2) { struct json_object_iter iter; struct json_object *sub; - assert(json_object_get_type(jso1) == json_type_object); - assert(json_object_get_type(jso2) == json_type_object); + assert(json_object_get_type(PUBLIC(jso1)) == json_type_object); + assert(json_object_get_type(PUBLIC(jso2)) == json_type_object); /* Iterate over jso1 keys and see if they exist and are equal in jso2 */ json_object_object_foreachC(jso1, iter) { - if (!lh_table_lookup_ex(jso2->o.c_object, (void *)iter.key, (void **)(void *)&sub)) + struct json_object_object *jso2_object = (struct json_object_object *)jso2; + if (!lh_table_lookup_ex(jso2_object->c_object, (void *)iter.key, (void **)(void *)&sub)) return 0; if (!json_object_equal(iter.val, sub)) return 0; @@ -1417,14 +1632,15 @@ static int json_object_all_values_equal(struct json_object *jso1, struct json_ob /* Iterate over jso2 keys to see if any exist that are not in jso1 */ json_object_object_foreachC(jso2, iter) { - if (!lh_table_lookup_ex(jso1->o.c_object, (void *)iter.key, (void **)(void *)&sub)) + struct json_object_object *jso1_object = (struct json_object_object *)jso1; + if (!lh_table_lookup_ex(jso1_object->c_object, (void *)iter.key, (void **)(void *)&sub)) return 0; } return 1; } -int json_object_equal(struct json_object *jso1, struct json_object *jso2) +static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2) { if (jso1 == jso2) return 1; @@ -1463,7 +1679,7 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) memcmp(get_string_component(jso1), get_string_component(jso2), jso1->o.c_string.len) == 0); - case json_type_object: return json_object_all_values_equal(jso1, jso2); + case json_type_object: assert(0); //return json_object_all_values_equal(jso1, jso2); case json_type_array: return json_array_equal(jso1, jso2); @@ -1472,6 +1688,70 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) return 0; } +int json_object_equal(struct json_object *jso1, struct json_object *jso2) +{ + if (jso1 == jso2) + return 1; + + if (!jso1 || !jso2) + return 0; + + // XAX cut this after conversion + if (!jso1->newold && !jso2->newold) + return Xjson_object_equal(jso1, jso2); // call old code + +#define jso1 ((struct json_object_base *)jso1) +#define jso2 ((struct json_object_base *)jso2) + if (jso1->o_type != jso2->o_type) + return 0; + + switch (jso1->o_type) + { + case json_type_boolean: return (JC_BOOL(jso1)->c_boolean == JC_BOOL(jso2)->c_boolean); + + case json_type_double: return (JC_DOUBLE(jso1)->c_double == JC_DOUBLE(jso2)->c_double); + + case json_type_int: + { + struct json_object_int *int1 = JC_INT(jso1); + struct json_object_int *int2 = JC_INT(jso2); + if (int1->cint_type == json_object_int_type_int64) + { + if (int2->cint_type == json_object_int_type_int64) + return (int1->cint.c_int64 == int2->cint.c_int64); + if (int1->cint.c_int64 < 0) + return 0; + return ((uint64_t)int1->cint.c_int64 == + int2->cint.c_uint64); + } + // else jso1 is a uint64 + if (int2->cint_type == json_object_int_type_uint64) + return (int1->cint.c_uint64 == int2->cint.c_uint64); + if (int2->cint.c_int64 < 0) + return 0; + return (int1->cint.c_uint64 == (uint64_t)int2->cint.c_int64); + } + + case json_type_string: + { + struct json_object_string *str1 = JC_STRING(jso1); + struct json_object_string *str2 = JC_STRING(jso2); + return (str1->len == str2->len && + memcmp(str1->data, str2->data, str1->len) == 0); + } + + case json_type_object: return json_object_all_values_equal(jso1, jso2); + +// XAX not actually + case json_type_array: return json_array_equal(PUBLIC(jso1), PUBLIC(jso2)); + + case json_type_null: return 1; + }; + + return 0; +#undef jso1 +#undef jso2 +} static int json_object_copy_serializer_data(struct json_object *src, struct json_object *dst) { @@ -1550,16 +1830,16 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha * * Note: caller is responsible for freeing *dst if this fails and returns -1. */ -static int json_object_deep_copy_recursive(struct json_object *src, struct json_object *parent, +static int json_object_deep_copy_recursive(struct json_object_base *src, struct json_object_base *parent, const char *key_in_parent, size_t index_in_parent, - struct json_object **dst, + struct json_object_base **dst, json_c_shallow_copy_fn *shallow_copy) { struct json_object_iter iter; size_t src_array_len, ii; int shallow_copy_rc = 0; - shallow_copy_rc = shallow_copy(src, parent, key_in_parent, index_in_parent, dst); + shallow_copy_rc = shallow_copy(PUBLIC(src), PUBLIC(parent), key_in_parent, index_in_parent, (struct json_object **)dst); // XAX remove cast too /* -1=error, 1=object created ok, 2=userdata set */ if (shallow_copy_rc < 1) { @@ -1573,44 +1853,44 @@ static int json_object_deep_copy_recursive(struct json_object *src, struct json_ case json_type_object: json_object_object_foreachC(src, iter) { - struct json_object *jso = NULL; + struct json_object_base *jso = NULL; /* This handles the `json_type_null` case */ if (!iter.val) jso = NULL; - else if (json_object_deep_copy_recursive(iter.val, src, iter.key, -1, &jso, + else if (json_object_deep_copy_recursive((struct json_object_base *)/*XAX removecast*/iter.val, src, iter.key, -1, &jso, shallow_copy) < 0) { - json_object_put(jso); + json_object_put(PUBLIC(jso)); return -1; } - if (json_object_object_add(*dst, iter.key, jso) < 0) + if (json_object_object_add(PUBLIC(*dst), iter.key, PUBLIC(jso)) < 0) { - json_object_put(jso); + json_object_put(PUBLIC(jso)); return -1; } } break; case json_type_array: - src_array_len = json_object_array_length(src); + src_array_len = json_object_array_length(PUBLIC(src)); for (ii = 0; ii < src_array_len; ii++) { - struct json_object *jso = NULL; - struct json_object *jso1 = json_object_array_get_idx(src, ii); + struct json_object_base *jso = NULL; + struct json_object_base *jso1 = (struct json_object_base *)/*XAXremovecast*/json_object_array_get_idx(PUBLIC(src), ii); /* This handles the `json_type_null` case */ if (!jso1) jso = NULL; else if (json_object_deep_copy_recursive(jso1, src, NULL, ii, &jso, shallow_copy) < 0) { - json_object_put(jso); + json_object_put(PUBLIC(jso)); return -1; } - if (json_object_array_add(*dst, jso) < 0) + if (json_object_array_add(PUBLIC(*dst), PUBLIC(jso)) < 0) { - json_object_put(jso); + json_object_put(PUBLIC(jso)); return -1; } } @@ -1622,7 +1902,7 @@ static int json_object_deep_copy_recursive(struct json_object *src, struct json_ } if (shallow_copy_rc != 2) - return json_object_copy_serializer_data(src, *dst); + return json_object_copy_serializer_data(PUBLIC(src), PUBLIC(*dst)); return 0; } @@ -1630,6 +1910,9 @@ static int json_object_deep_copy_recursive(struct json_object *src, struct json_ int json_object_deep_copy(struct json_object *src, struct json_object **dst, json_c_shallow_copy_fn *shallow_copy) { +#define src ((struct json_object_base *)src) +#define parent ((struct json_object_base *)parent) +#define dst ((struct json_object_base **)dst) int rc; /* Check if arguments are sane ; *dst must not point to a non-NULL object */ @@ -1645,11 +1928,14 @@ int json_object_deep_copy(struct json_object *src, struct json_object **dst, rc = json_object_deep_copy_recursive(src, NULL, NULL, -1, dst, shallow_copy); if (rc < 0) { - json_object_put(*dst); + json_object_put(PUBLIC(*dst)); *dst = NULL; } return rc; +#undef src +#undef parent +#undef dst } static void json_abort(const char *message) diff --git a/json_object.h b/json_object.h index 7c0d1f2..1805bda 100644 --- a/json_object.h +++ b/json_object.h @@ -490,8 +490,9 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key * @param obj the json_object instance * @param iter the object iterator, use type json_object_iter */ +// XAX temporary workaround during code conversion: #define json_object_object_foreachC(obj, iter) \ - for (iter.entry = json_object_get_object(obj)->head; \ + for (iter.entry = json_object_get_object(PUBLIC(obj))->head; \ (iter.entry ? (iter.key = (char *)lh_entry_k(iter.entry), \ iter.val = (struct json_object *)lh_entry_v(iter.entry), iter.entry) \ : 0); \ diff --git a/json_object_private.h b/json_object_private.h index 1c7737a..b6dfe0d 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -36,8 +36,60 @@ typedef enum json_object_int_type json_object_int_type_uint64 } json_object_int_type; +struct json_object_base // XAX rename to json_object after conversion +{ + int newold; // XAX temporary, remove after code conversion + enum json_type o_type; + uint32_t _ref_count; + json_object_private_delete_fn *_delete; + json_object_to_json_string_fn *_to_json_string; + struct printbuf *_pb; + json_object_delete_fn *_user_delete; + void *_userdata; + char data[1]; // Actually a struct json_object_${o_type} +}; + +struct json_object_object +{ + struct json_object_base base; + struct lh_table *c_object; +}; +struct json_object_array +{ + struct json_object_base base; + struct array_list *c_array; +}; + +struct json_object_boolean +{ + struct json_object_base base; + json_bool c_boolean; +}; +struct json_object_double +{ + struct json_object_base base; + json_bool c_double; +}; +struct json_object_int +{ + struct json_object_base base; + enum json_object_int_type cint_type; + union + { + int64_t c_int64; + uint64_t c_uint64; + } cint; +}; +struct json_object_string +{ + struct json_object_base base; + size_t len; + char data[1]; // Actually longer +}; + struct json_object { + int newold; enum json_type o_type; uint32_t _ref_count; json_object_private_delete_fn *_delete; @@ -56,7 +108,6 @@ struct json_object } cint; enum json_object_int_type cint_type; } c_int; - struct lh_table *c_object; struct array_list *c_array; struct { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a871573..5a8b2cc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,7 +20,8 @@ foreach(TESTNAME test_cast test_charcase test_compare - test_deep_copy +# XAX temporarily comment this out, until at least json_type_array is split out +# test_deep_copy test_double_serializer test_float test_int_add From 02b687b9a6e535591a360f109d1825db9a5a6b52 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 25 May 2020 03:44:56 +0000 Subject: [PATCH 12/94] Kick json_type_array out of struct json_object; re-enable the test_deep_copy test. --- json_object.c | 111 +++++++++++++++++++++++++++++++----------- json_object_private.h | 1 - tests/CMakeLists.txt | 3 +- 3 files changed, 83 insertions(+), 32 deletions(-) diff --git a/json_object.c b/json_object.c index 1219334..6d80762 100644 --- a/json_object.c +++ b/json_object.c @@ -73,6 +73,10 @@ static inline struct json_object_array *JC_ARRAY(struct json_object_base *jso) { return (void *)jso; } +static inline const struct json_object_array *JC_ARRAY_C(const struct json_object_base *jso) +{ + return (const void *)jso; +} static inline struct json_object_boolean *JC_BOOL(struct json_object_base *jso) { return (void *)jso; @@ -412,6 +416,8 @@ enum json_type json_object_get_type(const struct json_object *jso) void *json_object_get_userdata(json_object *jso) { + if (!jso->newold) + return jso ? jso->_userdata : NULL; #define jso ((const struct json_object_base *)jso) return jso ? jso->_userdata : NULL; #undef jso @@ -1464,13 +1470,14 @@ int json_object_set_string_len(json_object *jso, const char *s, int len) static int json_object_array_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { +#define jso ((struct json_object_base *)jso) int had_children = 0; size_t ii; printbuf_strappend(pb, "["); if (flags & JSON_C_TO_STRING_PRETTY) printbuf_strappend(pb, "\n"); - for (ii = 0; ii < json_object_array_length(jso); ii++) + for (ii = 0; ii < json_object_array_length(PUBLIC(jso)); ii++) { struct json_object *val; if (had_children) @@ -1483,7 +1490,7 @@ static int json_object_array_to_json_string(struct json_object *jso, struct prin if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) printbuf_strappend(pb, " "); indent(pb, level + 1, flags); - val = json_object_array_get_idx(jso, ii); + val = json_object_array_get_idx(PUBLIC(jso), ii); if (val == NULL) printbuf_strappend(pb, "null"); else if (val->_to_json_string(val, pb, level + 1, flags) < 0) @@ -1499,6 +1506,7 @@ static int json_object_array_to_json_string(struct json_object *jso, struct prin if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) return printbuf_strappend(pb, " ]"); return printbuf_strappend(pb, "]"); +#undef jso } static void json_object_array_entry_free(void *data) @@ -1508,86 +1516,104 @@ static void json_object_array_entry_free(void *data) static void json_object_array_delete(struct json_object *jso) { - array_list_free(jso->o.c_array); - json_object_generic_delete(jso); +#define jso ((struct json_object_base *)jso) + array_list_free(JC_ARRAY(jso)->c_array); + json_object_generic_delete(PUBLIC(jso)); +#undef jso } struct json_object *json_object_new_array(void) { - struct json_object *jso = json_object_new(json_type_array); - if (!jso) + struct json_object_base *jso_base; + jso_base = JSON_OBJECT_NEW(array, &json_object_array_delete); + if (!jso_base) return NULL; - jso->_delete = &json_object_array_delete; - jso->_to_json_string = &json_object_array_to_json_string; - jso->o.c_array = array_list_new(&json_object_array_entry_free); - if (jso->o.c_array == NULL) + struct json_object_array *jso = (struct json_object_array *)jso_base; + jso->c_array = array_list_new(&json_object_array_entry_free); + if (jso->c_array == NULL) { free(jso); return NULL; } - return jso; + return PUBLIC(jso_base); } struct array_list *json_object_get_array(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) if (!jso) return NULL; switch (jso->o_type) { - case json_type_array: return jso->o.c_array; + case json_type_array: return JC_ARRAY_C(jso)->c_array; default: return NULL; } +#undef jso } void json_object_array_sort(struct json_object *jso, int (*sort_fn)(const void *, const void *)) { - assert(json_object_get_type(jso) == json_type_array); - array_list_sort(jso->o.c_array, sort_fn); +#define jso ((struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC(jso)) == json_type_array); + array_list_sort(JC_ARRAY(jso)->c_array, sort_fn); +#undef jso } struct json_object *json_object_array_bsearch(const struct json_object *key, const struct json_object *jso, int (*sort_fn)(const void *, const void *)) { +#define jso ((const struct json_object_base *)jso) struct json_object **result; - assert(json_object_get_type(jso) == json_type_array); + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); result = (struct json_object **)array_list_bsearch((const void **)(void *)&key, - jso->o.c_array, sort_fn); + JC_ARRAY_C(jso)->c_array, sort_fn); if (!result) return NULL; return *result; +#undef jso } size_t json_object_array_length(const struct json_object *jso) { - assert(json_object_get_type(jso) == json_type_array); - return array_list_length(jso->o.c_array); +#define jso ((const struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + return array_list_length(JC_ARRAY_C(jso)->c_array); +#undef jso } int json_object_array_add(struct json_object *jso, struct json_object *val) { - assert(json_object_get_type(jso) == json_type_array); - return array_list_add(jso->o.c_array, val); +#define jso ((struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + return array_list_add(JC_ARRAY(jso)->c_array, val); +#undef jso } int json_object_array_put_idx(struct json_object *jso, size_t idx, struct json_object *val) { - assert(json_object_get_type(jso) == json_type_array); - return array_list_put_idx(jso->o.c_array, idx, val); +#define jso ((struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + return array_list_put_idx(JC_ARRAY(jso)->c_array, idx, val); +#undef jso } int json_object_array_del_idx(struct json_object *jso, size_t idx, size_t count) { - assert(json_object_get_type(jso) == json_type_array); - return array_list_del_idx(jso->o.c_array, idx, count); +#define jso ((struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + return array_list_del_idx(JC_ARRAY(jso)->c_array, idx, count); +#undef jso } struct json_object *json_object_array_get_idx(const struct json_object *jso, size_t idx) { - assert(json_object_get_type(jso) == json_type_array); - return (struct json_object *)array_list_get_idx(jso->o.c_array, idx); +#define jso ((const struct json_object_base *)jso) + assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + return (struct json_object *)array_list_get_idx(JC_ARRAY_C(jso)->c_array, idx); +#undef jso } static int json_array_equal(struct json_object *jso1, struct json_object *jso2) @@ -1681,7 +1707,7 @@ static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2 case json_type_object: assert(0); //return json_object_all_values_equal(jso1, jso2); - case json_type_array: return json_array_equal(jso1, jso2); + case json_type_array: assert(0); //return json_array_equal(jso1, jso2); case json_type_null: return 1; }; @@ -1742,7 +1768,6 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) case json_type_object: return json_object_all_values_equal(jso1, jso2); -// XAX not actually case json_type_array: return json_array_equal(PUBLIC(jso1), PUBLIC(jso2)); case json_type_null: return 1; @@ -1753,7 +1778,8 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) #undef jso2 } -static int json_object_copy_serializer_data(struct json_object *src, struct json_object *dst) +// XAX remove this function after code conversion +static int Xjson_object_copy_serializer_data(struct json_object *src, struct json_object *dst) { if (!src->_userdata && !src->_user_delete) return 0; @@ -1774,6 +1800,33 @@ static int json_object_copy_serializer_data(struct json_object *src, struct json dst->_user_delete = src->_user_delete; return 0; } +static int json_object_copy_serializer_data(struct json_object *src, struct json_object *dst) +{ + if (!src->newold) + return Xjson_object_copy_serializer_data(src, dst); +#define src ((struct json_object_base *)src) +#define dst ((struct json_object_base *)dst) + if (!src->_userdata && !src->_user_delete) + return 0; + + if (dst->_to_json_string == json_object_userdata_to_json_string || + dst->_to_json_string == _json_object_userdata_to_json_string) + { + dst->_userdata = strdup(src->_userdata); + } + // else if ... other supported serializers ... + else + { + _json_c_set_last_err( + "json_object_deep_copy: unable to copy unknown serializer data: %p\n", + dst->_to_json_string); + return -1; + } + dst->_user_delete = src->_user_delete; + return 0; +#undef src +#undef dst +} /** * The default shallow copy implementation. Simply creates a new object of the same diff --git a/json_object_private.h b/json_object_private.h index b6dfe0d..45e7bc6 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -108,7 +108,6 @@ struct json_object } cint; enum json_object_int_type cint_type; } c_int; - struct array_list *c_array; struct { union diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5a8b2cc..a871573 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,8 +20,7 @@ foreach(TESTNAME test_cast test_charcase test_compare -# XAX temporarily comment this out, until at least json_type_array is split out -# test_deep_copy + test_deep_copy test_double_serializer test_float test_int_add From 5d89fc8a9d1c926ab341f49f41be1c38c7049161 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 25 May 2020 03:52:36 +0000 Subject: [PATCH 13/94] Add some backwards compat for Visual Studio 2013. --- json_object.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/json_object.c b/json_object.c index 6d80762..9b4df33 100644 --- a/json_object.c +++ b/json_object.c @@ -48,6 +48,11 @@ static void json_object_generic_delete(struct json_object *jso); static void Xjson_object_generic_delete(struct json_object_base *jso); static struct json_object *json_object_new(enum json_type o_type); +#if defined(_MSC_VER) && (_MSC_VER <= 1800) +/* VS2013 doesn't know about "inline" */ +#define inline __inline +#endif + // XAX kill this once json_object_base is renamed back to json_object static inline struct json_object *PUBLIC(struct json_object_base *jso) { From d1f83bf5eab331e3014f04e856bcb3662da1199f Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 25 May 2020 04:04:02 +0000 Subject: [PATCH 14/94] Kick json_type_boolean out of struct json_object. --- json_object.c | 51 ++++++++++++++++++++++++++++++------------- json_object_private.h | 1 - 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/json_object.c b/json_object.c index 9b4df33..b2d8d18 100644 --- a/json_object.c +++ b/json_object.c @@ -86,6 +86,10 @@ static inline struct json_object_boolean *JC_BOOL(struct json_object_base *jso) { return (void *)jso; } +static inline const struct json_object_boolean *JC_BOOL_C(const struct json_object_base *jso) +{ + return (const void *)jso; +} static inline struct json_object_double *JC_DOUBLE(struct json_object_base *jso) { return (void *)jso; @@ -786,25 +790,27 @@ void json_object_object_del(struct json_object *jso, const char *key) #undef jso } -// XAX ------------------------------ start unconverted code: /* json_object_boolean */ static int json_object_boolean_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { - if (jso->o.c_boolean) +#define jso ((struct json_object_base *)jso) + if (JC_BOOL(jso)->c_boolean) return printbuf_strappend(pb, "true"); return printbuf_strappend(pb, "false"); +#undef jso } struct json_object *json_object_new_boolean(json_bool b) { - struct json_object *jso = json_object_new(json_type_boolean); - if (!jso) + struct json_object_base *jso_base; + jso_base = JSON_OBJECT_NEW(boolean, &json_object_generic_delete); + if (!jso_base) return NULL; - jso->_to_json_string = &json_object_boolean_to_json_string; - jso->o.c_boolean = b; - return jso; + struct json_object_boolean *jso = (struct json_object_boolean *)jso_base; + jso->c_boolean = b; + return PUBLIC(jso_base); } json_bool json_object_get_boolean(const struct json_object *jso) @@ -813,7 +819,9 @@ json_bool json_object_get_boolean(const struct json_object *jso) return 0; switch (jso->o_type) { - case json_type_boolean: return jso->o.c_boolean; +#define jso ((const struct json_object_base *)jso) + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; +#undef jso case json_type_int: switch (jso->o.c_int.cint_type) { @@ -829,12 +837,15 @@ json_bool json_object_get_boolean(const struct json_object *jso) int json_object_set_boolean(struct json_object *jso, json_bool new_value) { +#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_boolean) return 0; - jso->o.c_boolean = new_value; + JC_BOOL(jso)->c_boolean = new_value; return 1; +#undef jso } +// XAX ------------------------------ start unconverted code: /* json_object_int */ static int json_object_int_to_json_string(struct json_object *jso, struct printbuf *pb, int level, @@ -907,7 +918,9 @@ int32_t json_object_get_int(const struct json_object *jso) if (jso->o.c_double >= INT32_MAX) return INT32_MAX; return (int32_t)jso->o.c_double; - case json_type_boolean: return jso->o.c_boolean; +#define jso ((const struct json_object_base *)jso) + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; +#undef jso default: return 0; } } @@ -965,7 +978,9 @@ int64_t json_object_get_int64(const struct json_object *jso) if (jso->o.c_double <= INT64_MIN) return INT64_MIN; return (int64_t)jso->o.c_double; - case json_type_boolean: return jso->o.c_boolean; +#define jso ((const struct json_object_base *)jso) + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; +#undef jso case json_type_string: if (json_parse_int64(get_string_component(jso), &cint) == 0) return cint; @@ -1000,7 +1015,9 @@ uint64_t json_object_get_uint64(const struct json_object *jso) if (jso->o.c_double < 0) return 0; return (uint64_t)jso->o.c_double; - case json_type_boolean: return jso->o.c_boolean; +#define jso ((const struct json_object_base *)jso) + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; +#undef jso case json_type_string: if (json_parse_uint64(get_string_component(jso), &cuint) == 0) return cuint; @@ -1294,7 +1311,9 @@ double json_object_get_double(const struct json_object *jso) case json_object_int_type_uint64: return jso->o.c_int.cint.c_uint64; default: json_abort("invalid cint_type"); } - case json_type_boolean: return jso->o.c_boolean; +#define jso ((const struct json_object_base *)jso) + case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; +#undef jso case json_type_string: errno = 0; cdouble = strtod(get_string_component(jso), &errPtr); @@ -1684,7 +1703,7 @@ static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2 switch (jso1->o_type) { - case json_type_boolean: return (jso1->o.c_boolean == jso2->o.c_boolean); + case json_type_boolean: assert(0); //return (jso1->o.c_boolean == jso2->o.c_boolean); case json_type_double: return (jso1->o.c_double == jso2->o.c_double); @@ -1846,7 +1865,9 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha { switch (src->o_type) { - case json_type_boolean: *dst = json_object_new_boolean(src->o.c_boolean); break; +#define src ((struct json_object_base *)src) + case json_type_boolean: *dst = json_object_new_boolean(JC_BOOL(src)->c_boolean); break; +#undef src case json_type_double: *dst = json_object_new_double(src->o.c_double); break; diff --git a/json_object_private.h b/json_object_private.h index 45e7bc6..0f6a4f8 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -97,7 +97,6 @@ struct json_object struct printbuf *_pb; union data { - json_bool c_boolean; double c_double; struct { From 0351bb55c85ab8db545327af3d872fb63e2838b1 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 25 May 2020 04:10:11 +0000 Subject: [PATCH 15/94] Declare variables earlier, to appease Visual Studio 2010. --- json_object.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/json_object.c b/json_object.c index b2d8d18..f648c5c 100644 --- a/json_object.c +++ b/json_object.c @@ -665,10 +665,11 @@ static void json_object_object_delete(struct json_object_base *jso_base) struct json_object *json_object_new_object(void) { struct json_object_base *jso_base; + struct json_object_object *jso; jso_base = JSON_OBJECT_NEW(object, &json_object_object_delete); if (!jso_base) return NULL; - struct json_object_object *jso = (struct json_object_object *)jso_base; + jso = (struct json_object_object *)jso_base; jso->c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, &json_object_lh_entry_free); if (!jso->c_object) @@ -805,10 +806,11 @@ static int json_object_boolean_to_json_string(struct json_object *jso, struct pr struct json_object *json_object_new_boolean(json_bool b) { struct json_object_base *jso_base; + struct json_object_boolean *jso; jso_base = JSON_OBJECT_NEW(boolean, &json_object_generic_delete); if (!jso_base) return NULL; - struct json_object_boolean *jso = (struct json_object_boolean *)jso_base; + jso = (struct json_object_boolean *)jso_base; jso->c_boolean = b; return PUBLIC(jso_base); } @@ -1549,10 +1551,11 @@ static void json_object_array_delete(struct json_object *jso) struct json_object *json_object_new_array(void) { struct json_object_base *jso_base; + struct json_object_array *jso; jso_base = JSON_OBJECT_NEW(array, &json_object_array_delete); if (!jso_base) return NULL; - struct json_object_array *jso = (struct json_object_array *)jso_base; + jso = (struct json_object_array *)jso_base; jso->c_array = array_list_new(&json_object_array_entry_free); if (jso->c_array == NULL) { From 9ecb1222bd18801f0da2acbe9021f04ed74f0dfa Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 26 May 2020 02:31:35 +0000 Subject: [PATCH 16/94] Kick json_type_int and json_type_double out of struct json_object. Clean up the code in json_object_new_* a bit by dropping unnecesary json_object_base variables. --- json_object.c | 305 ++++++++++++++++++--------------- json_object_private.h | 12 +- tests/test_double_serializer.c | 2 +- 3 files changed, 172 insertions(+), 147 deletions(-) diff --git a/json_object.c b/json_object.c index f648c5c..5300448 100644 --- a/json_object.c +++ b/json_object.c @@ -94,20 +94,32 @@ static inline struct json_object_double *JC_DOUBLE(struct json_object_base *jso) { return (void *)jso; } +static inline const struct json_object_double *JC_DOUBLE_C(const struct json_object_base *jso) +{ + return (const void *)jso; +} static inline struct json_object_int *JC_INT(struct json_object_base *jso) { return (void *)jso; } +static inline const struct json_object_int *JC_INT_C(const struct json_object_base *jso) +{ + return (const void *)jso; +} static inline struct json_object_string *JC_STRING(struct json_object_base *jso) { return (void *)jso; } +static inline const struct json_object_string *JC_STRING_C(const struct json_object_base *jso) +{ + return (const void *)jso; +} #define JC_CONCAT(a,b) a##b #define JC_CONCAT3(a,b,c) a##b##c #define JSON_OBJECT_NEW(jtype, delete_fn) \ - Xjson_object_new(JC_CONCAT(json_type_,jtype), \ + (struct JC_CONCAT(json_object_,jtype) *)Xjson_object_new(JC_CONCAT(json_type_,jtype), \ sizeof(struct JC_CONCAT(json_object_,jtype)), \ &JC_CONCAT3(json_object_,jtype,_to_json_string), \ (void *)delete_fn) // XAX drop cast @@ -657,28 +669,24 @@ static void json_object_lh_entry_free(struct lh_entry *ent) static void json_object_object_delete(struct json_object_base *jso_base) { - struct json_object_object *jso = (struct json_object_object *)jso_base; - lh_table_free(jso->c_object); + lh_table_free(JC_OBJECT(jso_base)->c_object); Xjson_object_generic_delete(jso_base); } struct json_object *json_object_new_object(void) { - struct json_object_base *jso_base; - struct json_object_object *jso; - jso_base = JSON_OBJECT_NEW(object, &json_object_object_delete); - if (!jso_base) + struct json_object_object *jso = JSON_OBJECT_NEW(object, &json_object_object_delete); + if (!jso) return NULL; - jso = (struct json_object_object *)jso_base; jso->c_object = lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, &json_object_lh_entry_free); if (!jso->c_object) { - Xjson_object_generic_delete(jso_base); + Xjson_object_generic_delete(&jso->base); errno = ENOMEM; return NULL; } - return PUBLIC(jso_base); + return PUBLIC(&jso->base); } struct lh_table *json_object_get_object(const struct json_object *jso) @@ -805,14 +813,11 @@ static int json_object_boolean_to_json_string(struct json_object *jso, struct pr struct json_object *json_object_new_boolean(json_bool b) { - struct json_object_base *jso_base; - struct json_object_boolean *jso; - jso_base = JSON_OBJECT_NEW(boolean, &json_object_generic_delete); - if (!jso_base) + struct json_object_boolean *jso = JSON_OBJECT_NEW(boolean, &json_object_generic_delete); + if (!jso) return NULL; - jso = (struct json_object_boolean *)jso_base; jso->c_boolean = b; - return PUBLIC(jso_base); + return PUBLIC(&jso->base); } json_bool json_object_get_boolean(const struct json_object *jso) @@ -823,15 +828,15 @@ json_bool json_object_get_boolean(const struct json_object *jso) { #define jso ((const struct json_object_base *)jso) case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; -#undef jso case json_type_int: - switch (jso->o.c_int.cint_type) + switch (JC_INT_C(jso)->cint_type) { - case json_object_int_type_int64: return (jso->o.c_int.cint.c_int64 != 0); - case json_object_int_type_uint64: return (jso->o.c_int.cint.c_uint64 != 0); + case json_object_int_type_int64: return (JC_INT_C(jso)->cint.c_int64 != 0); + case json_object_int_type_uint64: return (JC_INT_C(jso)->cint.c_uint64 != 0); default: json_abort("invalid cint_type"); } - case json_type_double: return (jso->o.c_double != 0); + case json_type_double: return (JC_DOUBLE_C(jso)->c_double != 0); +#undef jso case json_type_string: return (jso->o.c_string.len != 0); default: return 0; } @@ -847,60 +852,60 @@ int json_object_set_boolean(struct json_object *jso, json_bool new_value) #undef jso } -// XAX ------------------------------ start unconverted code: /* json_object_int */ static int json_object_int_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { +#define jso ((struct json_object_base *)jso) /* room for 19 digits, the sign char, and a null term */ char sbuf[21]; - if (jso->o.c_int.cint_type == json_object_int_type_int64) - snprintf(sbuf, sizeof(sbuf), "%" PRId64, jso->o.c_int.cint.c_int64); + if (JC_INT(jso)->cint_type == json_object_int_type_int64) + snprintf(sbuf, sizeof(sbuf), "%" PRId64, JC_INT(jso)->cint.c_int64); else - snprintf(sbuf, sizeof(sbuf), "%" PRIu64, jso->o.c_int.cint.c_uint64); + snprintf(sbuf, sizeof(sbuf), "%" PRIu64, JC_INT(jso)->cint.c_uint64); return printbuf_memappend(pb, sbuf, strlen(sbuf)); +#undef jso } struct json_object *json_object_new_int(int32_t i) { - struct json_object *jso = json_object_new(json_type_int); - if (!jso) - return NULL; - jso->_to_json_string = &json_object_int_to_json_string; - jso->o.c_int.cint.c_int64 = i; - jso->o.c_int.cint_type = json_object_int_type_int64; - return jso; + return json_object_new_int64(i); } int32_t json_object_get_int(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) int64_t cint64; + double cdouble; enum json_type o_type; if (!jso) return 0; o_type = jso->o_type; - if (jso->o.c_int.cint_type == json_object_int_type_int64) + if (o_type == json_type_int) { - cint64 = jso->o.c_int.cint.c_int64; - } - else - { - if (jso->o.c_int.cint.c_uint64 >= INT64_MAX) - cint64 = INT64_MAX; + const struct json_object_int *jsoint = JC_INT_C(jso); + if (jsoint->cint_type == json_object_int_type_int64) + { + cint64 = jsoint->cint.c_int64; + } else - cint64 = (int64_t)jso->o.c_int.cint.c_uint64; + { + if (jsoint->cint.c_uint64 >= INT64_MAX) + cint64 = INT64_MAX; + else + cint64 = (int64_t)jsoint->cint.c_uint64; + } } - - if (o_type == json_type_string) + else if (o_type == json_type_string) { /* * Parse strings into 64-bit numbers, then use the * 64-to-32-bit number handling below. */ - if (json_parse_int64(get_string_component(jso), &cint64) != 0) + if (json_parse_int64(get_string_component(PUBLIC_C(jso)), &cint64) != 0) return 0; /* whoops, it didn't work. */ o_type = json_type_int; } @@ -915,16 +920,16 @@ int32_t json_object_get_int(const struct json_object *jso) return INT32_MAX; return (int32_t)cint64; case json_type_double: - if (jso->o.c_double <= INT32_MIN) + cdouble = JC_DOUBLE_C(jso)->c_double; + if (cdouble <= INT32_MIN) return INT32_MIN; - if (jso->o.c_double >= INT32_MAX) + if (cdouble >= INT32_MAX) return INT32_MAX; - return (int32_t)jso->o.c_double; -#define jso ((const struct json_object_base *)jso) + return (int32_t)cdouble; case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; -#undef jso default: return 0; } +#undef jso } int json_object_set_int(struct json_object *jso, int new_value) @@ -934,28 +939,27 @@ int json_object_set_int(struct json_object *jso, int new_value) struct json_object *json_object_new_int64(int64_t i) { - struct json_object *jso = json_object_new(json_type_int); + struct json_object_int *jso = JSON_OBJECT_NEW(int, &json_object_generic_delete); if (!jso) return NULL; - jso->_to_json_string = &json_object_int_to_json_string; - jso->o.c_int.cint.c_int64 = i; - jso->o.c_int.cint_type = json_object_int_type_int64; - return jso; + jso->cint.c_int64 = i; + jso->cint_type = json_object_int_type_int64; + return PUBLIC(&jso->base); } struct json_object *json_object_new_uint64(uint64_t i) { - struct json_object *jso = json_object_new(json_type_int); + struct json_object_int *jso = JSON_OBJECT_NEW(int, &json_object_generic_delete); if (!jso) return NULL; - jso->_to_json_string = &json_object_int_to_json_string; - jso->o.c_int.cint.c_uint64 = i; - jso->o.c_int.cint_type = json_object_int_type_uint64; - return jso; + jso->cint.c_uint64 = i; + jso->cint_type = json_object_int_type_uint64; + return PUBLIC(&jso->base); } int64_t json_object_get_int64(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) int64_t cint; if (!jso) @@ -963,36 +967,39 @@ int64_t json_object_get_int64(const struct json_object *jso) switch (jso->o_type) { case json_type_int: - switch (jso->o.c_int.cint_type) + { + const struct json_object_int *jsoint = JC_INT_C(jso); + switch (jsoint->cint_type) { - case json_object_int_type_int64: return jso->o.c_int.cint.c_int64; + case json_object_int_type_int64: return jsoint->cint.c_int64; case json_object_int_type_uint64: - if (jso->o.c_int.cint.c_uint64 >= INT64_MAX) + if (jsoint->cint.c_uint64 >= INT64_MAX) return INT64_MAX; - return (int64_t)jso->o.c_int.cint.c_uint64; + return (int64_t)jsoint->cint.c_uint64; default: json_abort("invalid cint_type"); } + } case json_type_double: // INT64_MAX can't be exactly represented as a double // so cast to tell the compiler it's ok to round up. - if (jso->o.c_double >= (double)INT64_MAX) + if (JC_DOUBLE_C(jso)->c_double >= (double)INT64_MAX) return INT64_MAX; - if (jso->o.c_double <= INT64_MIN) + if (JC_DOUBLE_C(jso)->c_double <= INT64_MIN) return INT64_MIN; - return (int64_t)jso->o.c_double; -#define jso ((const struct json_object_base *)jso) + return (int64_t)JC_DOUBLE_C(jso)->c_double; case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; -#undef jso case json_type_string: - if (json_parse_int64(get_string_component(jso), &cint) == 0) + if (json_parse_int64(get_string_component(PUBLIC_C(jso)), &cint) == 0) return cint; /* FALLTHRU */ default: return 0; } +#undef jso } uint64_t json_object_get_uint64(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) uint64_t cuint; if (!jso) @@ -1000,95 +1007,105 @@ uint64_t json_object_get_uint64(const struct json_object *jso) switch (jso->o_type) { case json_type_int: - switch (jso->o.c_int.cint_type) + { + const struct json_object_int *jsoint = JC_INT_C(jso); + switch (jsoint->cint_type) { case json_object_int_type_int64: - if (jso->o.c_int.cint.c_int64 < 0) + if (jsoint->cint.c_int64 < 0) return 0; - return (uint64_t)jso->o.c_int.cint.c_int64; - case json_object_int_type_uint64: return jso->o.c_int.cint.c_uint64; + return (uint64_t)jsoint->cint.c_int64; + case json_object_int_type_uint64: return jsoint->cint.c_uint64; default: json_abort("invalid cint_type"); } + } case json_type_double: // UINT64_MAX can't be exactly represented as a double // so cast to tell the compiler it's ok to round up. - if (jso->o.c_double >= (double)UINT64_MAX) + if (JC_DOUBLE_C(jso)->c_double >= (double)UINT64_MAX) return UINT64_MAX; - if (jso->o.c_double < 0) + if (JC_DOUBLE_C(jso)->c_double < 0) return 0; - return (uint64_t)jso->o.c_double; -#define jso ((const struct json_object_base *)jso) + return (uint64_t)JC_DOUBLE_C(jso)->c_double; case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; -#undef jso case json_type_string: - if (json_parse_uint64(get_string_component(jso), &cuint) == 0) + if (json_parse_uint64(get_string_component(PUBLIC_C(jso)), &cuint) == 0) return cuint; /* FALLTHRU */ default: return 0; } +#undef jso } int json_object_set_int64(struct json_object *jso, int64_t new_value) { +#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_int) return 0; - jso->o.c_int.cint.c_int64 = new_value; - jso->o.c_int.cint_type = json_object_int_type_int64; + JC_INT(jso)->cint.c_int64 = new_value; + JC_INT(jso)->cint_type = json_object_int_type_int64; return 1; +#undef jso } int json_object_set_uint64(struct json_object *jso, uint64_t new_value) { +#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_int) return 0; - jso->o.c_int.cint.c_uint64 = new_value; - jso->o.c_int.cint_type = json_object_int_type_uint64; + JC_INT(jso)->cint.c_uint64 = new_value; + JC_INT(jso)->cint_type = json_object_int_type_uint64; return 1; +#undef jso } int json_object_int_inc(struct json_object *jso, int64_t val) { +#define jso ((struct json_object_base *)jso) + struct json_object_int *jsoint; if (!jso || jso->o_type != json_type_int) return 0; - switch (jso->o.c_int.cint_type) + jsoint = JC_INT(jso); + switch (jsoint->cint_type) { case json_object_int_type_int64: - if (val > 0 && jso->o.c_int.cint.c_int64 > INT64_MAX - val) + if (val > 0 && jsoint->cint.c_int64 > INT64_MAX - val) { - jso->o.c_int.cint.c_uint64 = - (uint64_t)jso->o.c_int.cint.c_int64 + (uint64_t)val; - jso->o.c_int.cint_type = json_object_int_type_uint64; + jsoint->cint.c_uint64 = + (uint64_t)jsoint->cint.c_int64 + (uint64_t)val; + jsoint->cint_type = json_object_int_type_uint64; } - else if (val < 0 && jso->o.c_int.cint.c_int64 < INT64_MIN - val) + else if (val < 0 && jsoint->cint.c_int64 < INT64_MIN - val) { - jso->o.c_int.cint.c_int64 = INT64_MIN; + jsoint->cint.c_int64 = INT64_MIN; } else { - jso->o.c_int.cint.c_int64 += val; + jsoint->cint.c_int64 += val; } return 1; case json_object_int_type_uint64: - if (val > 0 && jso->o.c_int.cint.c_uint64 > UINT64_MAX - (uint64_t)val) + if (val > 0 && jsoint->cint.c_uint64 > UINT64_MAX - (uint64_t)val) { - jso->o.c_int.cint.c_uint64 = UINT64_MAX; + jsoint->cint.c_uint64 = UINT64_MAX; } - else if (val < 0 && jso->o.c_int.cint.c_uint64 < (uint64_t)(-val)) + else if (val < 0 && jsoint->cint.c_uint64 < (uint64_t)(-val)) { - jso->o.c_int.cint.c_int64 = (int64_t)jso->o.c_int.cint.c_uint64 + val; - jso->o.c_int.cint_type = json_object_int_type_int64; + jsoint->cint.c_int64 = (int64_t)jsoint->cint.c_uint64 + val; + jsoint->cint_type = json_object_int_type_int64; } - else if (val < 0 && jso->o.c_int.cint.c_uint64 >= (uint64_t)(-val)) + else if (val < 0 && jsoint->cint.c_uint64 >= (uint64_t)(-val)) { - jso->o.c_int.cint.c_uint64 -= (uint64_t)(-val); + jsoint->cint.c_uint64 -= (uint64_t)(-val); } else { - jso->o.c_int.cint.c_uint64 += val; + jsoint->cint.c_uint64 += val; } return 1; default: json_abort("invalid cint_type"); } +#undef jso } /* json_object_double */ @@ -1140,6 +1157,8 @@ int json_c_set_serialization_double_format(const char *double_format, int global static int json_object_double_to_json_string_format(struct json_object *jso, struct printbuf *pb, int level, int flags, const char *format) { +#define jso ((struct json_object_base *)jso) + struct json_object_double *jsodbl = JC_DOUBLE(jso); char buf[128], *p, *q; int size; /* Although JSON RFC does not support @@ -1147,13 +1166,13 @@ static int json_object_double_to_json_string_format(struct json_object *jso, str * ECMA 262 section 9.8.1 defines * how to handle these cases as strings */ - if (isnan(jso->o.c_double)) + if (isnan(jsodbl->c_double)) { size = snprintf(buf, sizeof(buf), "NaN"); } - else if (isinf(jso->o.c_double)) + else if (isinf(jsodbl->c_double)) { - if (jso->o.c_double > 0) + if (jsodbl->c_double > 0) size = snprintf(buf, sizeof(buf), "Infinity"); else size = snprintf(buf, sizeof(buf), "-Infinity"); @@ -1176,7 +1195,7 @@ static int json_object_double_to_json_string_format(struct json_object *jso, str else format = std_format; } - size = snprintf(buf, sizeof(buf), format, jso->o.c_double); + size = snprintf(buf, sizeof(buf), format, jsodbl->c_double); if (size < 0) return -1; @@ -1228,29 +1247,34 @@ static int json_object_double_to_json_string_format(struct json_object *jso, str size = sizeof(buf) - 1; printbuf_memappend(pb, buf, size); return size; +#undef jso } static int json_object_double_to_json_string_default(struct json_object *jso, struct printbuf *pb, int level, int flags) { - return json_object_double_to_json_string_format(jso, pb, level, flags, NULL); +#define jso ((struct json_object_base *)jso) + return json_object_double_to_json_string_format(PUBLIC(jso), pb, level, flags, NULL); +#undef jso } int json_object_double_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { - return json_object_double_to_json_string_format(jso, pb, level, flags, +#define jso ((struct json_object_base *)jso) + return json_object_double_to_json_string_format(PUBLIC(jso), pb, level, flags, (const char *)jso->_userdata); +#undef jso } struct json_object *json_object_new_double(double d) { - struct json_object *jso = json_object_new(json_type_double); + struct json_object_double *jso = JSON_OBJECT_NEW(double, &json_object_generic_delete); if (!jso) return NULL; - jso->_to_json_string = &json_object_double_to_json_string_default; - jso->o.c_double = d; - return jso; + jso->base._to_json_string = &json_object_double_to_json_string_default; + jso->c_double = d; + return PUBLIC(&jso->base); } struct json_object *json_object_new_double_s(double d, const char *ds) @@ -1286,9 +1310,21 @@ static int _json_object_userdata_to_json_string(struct json_object *jso, struct int json_object_userdata_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { + // XAX old code compat, remove this + if (!jso->newold) + { + int userdata_len = strlen((const char *)jso->_userdata); + printbuf_memappend(pb, (const char *)jso->_userdata, userdata_len); + return userdata_len; + } + else + { +#define jso ((const struct json_object_base *)jso) int userdata_len = strlen((const char *)jso->_userdata); printbuf_memappend(pb, (const char *)jso->_userdata, userdata_len); return userdata_len; +#undef jso + } } void json_object_free_userdata(struct json_object *jso, void *userdata) @@ -1298,6 +1334,7 @@ void json_object_free_userdata(struct json_object *jso, void *userdata) double json_object_get_double(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) double cdouble; char *errPtr = NULL; @@ -1305,23 +1342,21 @@ double json_object_get_double(const struct json_object *jso) return 0.0; switch (jso->o_type) { - case json_type_double: return jso->o.c_double; + case json_type_double: return JC_DOUBLE_C(jso)->c_double; case json_type_int: - switch (jso->o.c_int.cint_type) + switch (JC_INT_C(jso)->cint_type) { - case json_object_int_type_int64: return jso->o.c_int.cint.c_int64; - case json_object_int_type_uint64: return jso->o.c_int.cint.c_uint64; + case json_object_int_type_int64: return JC_INT_C(jso)->cint.c_int64; + case json_object_int_type_uint64: return JC_INT_C(jso)->cint.c_uint64; default: json_abort("invalid cint_type"); } -#define jso ((const struct json_object_base *)jso) case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; -#undef jso case json_type_string: errno = 0; - cdouble = strtod(get_string_component(jso), &errPtr); + cdouble = strtod(get_string_component(PUBLIC_C(jso)), &errPtr); /* if conversion stopped at the first character, return 0.0 */ - if (errPtr == get_string_component(jso)) + if (errPtr == get_string_component(PUBLIC_C(jso))) { errno = EINVAL; return 0.0; @@ -1354,16 +1389,19 @@ double json_object_get_double(const struct json_object *jso) return cdouble; default: errno = EINVAL; return 0.0; } +#undef jso } int json_object_set_double(struct json_object *jso, double new_value) { +#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_double) return 0; - jso->o.c_double = new_value; + JC_DOUBLE(jso)->c_double = new_value; if (jso->_to_json_string == &_json_object_userdata_to_json_string) - json_object_set_serializer(jso, NULL, NULL, NULL); + json_object_set_serializer(PUBLIC(jso), NULL, NULL, NULL); return 1; +#undef jso } /* json_object_string */ @@ -1550,19 +1588,16 @@ static void json_object_array_delete(struct json_object *jso) struct json_object *json_object_new_array(void) { - struct json_object_base *jso_base; - struct json_object_array *jso; - jso_base = JSON_OBJECT_NEW(array, &json_object_array_delete); - if (!jso_base) + struct json_object_array *jso = JSON_OBJECT_NEW(array, &json_object_array_delete); + if (!jso) return NULL; - jso = (struct json_object_array *)jso_base; jso->c_array = array_list_new(&json_object_array_entry_free); if (jso->c_array == NULL) { free(jso); return NULL; } - return PUBLIC(jso_base); + return PUBLIC(&jso->base); } struct array_list *json_object_get_array(const struct json_object *jso) @@ -1675,8 +1710,7 @@ static int json_object_all_values_equal(struct json_object_base *jso1, struct js /* Iterate over jso1 keys and see if they exist and are equal in jso2 */ json_object_object_foreachC(jso1, iter) { - struct json_object_object *jso2_object = (struct json_object_object *)jso2; - if (!lh_table_lookup_ex(jso2_object->c_object, (void *)iter.key, (void **)(void *)&sub)) + if (!lh_table_lookup_ex(JC_OBJECT(jso2)->c_object, (void *)iter.key, (void **)(void *)&sub)) return 0; if (!json_object_equal(iter.val, sub)) return 0; @@ -1685,8 +1719,7 @@ static int json_object_all_values_equal(struct json_object_base *jso1, struct js /* Iterate over jso2 keys to see if any exist that are not in jso1 */ json_object_object_foreachC(jso2, iter) { - struct json_object_object *jso1_object = (struct json_object_object *)jso1; - if (!lh_table_lookup_ex(jso1_object->c_object, (void *)iter.key, (void **)(void *)&sub)) + if (!lh_table_lookup_ex(JC_OBJECT(jso1)->c_object, (void *)iter.key, (void **)(void *)&sub)) return 0; } @@ -1708,9 +1741,10 @@ static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2 { case json_type_boolean: assert(0); //return (jso1->o.c_boolean == jso2->o.c_boolean); - case json_type_double: return (jso1->o.c_double == jso2->o.c_double); + case json_type_double: assert(0); // return (jso1->o.c_double == jso2->o.c_double); - case json_type_int: + case json_type_int: assert(0); + /* if (jso1->o.c_int.cint_type == json_object_int_type_int64) { if (jso2->o.c_int.cint_type == json_object_int_type_int64) @@ -1726,6 +1760,7 @@ static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2 if (jso2->o.c_int.cint.c_int64 < 0) return 0; return (jso1->o.c_int.cint.c_uint64 == (uint64_t)jso2->o.c_int.cint.c_int64); + */ case json_type_string: return (jso1->o.c_string.len == jso2->o.c_string.len && @@ -1870,22 +1905,22 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha { #define src ((struct json_object_base *)src) case json_type_boolean: *dst = json_object_new_boolean(JC_BOOL(src)->c_boolean); break; -#undef src - case json_type_double: *dst = json_object_new_double(src->o.c_double); break; + case json_type_double: *dst = json_object_new_double(JC_DOUBLE(src)->c_double); break; case json_type_int: - switch (src->o.c_int.cint_type) + switch (JC_INT(src)->cint_type) { case json_object_int_type_int64: - *dst = json_object_new_int64(src->o.c_int.cint.c_int64); + *dst = json_object_new_int64(JC_INT(src)->cint.c_int64); break; case json_object_int_type_uint64: - *dst = json_object_new_uint64(src->o.c_int.cint.c_uint64); + *dst = json_object_new_uint64(JC_INT(src)->cint.c_uint64); break; default: json_abort("invalid cint_type"); } break; +#undef src case json_type_string: *dst = json_object_new_string(get_string_component(src)); break; diff --git a/json_object_private.h b/json_object_private.h index 0f6a4f8..5ea865c 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -68,7 +68,7 @@ struct json_object_boolean struct json_object_double { struct json_object_base base; - json_bool c_double; + double c_double; }; struct json_object_int { @@ -97,16 +97,6 @@ struct json_object struct printbuf *_pb; union data { - double c_double; - struct - { - union - { - int64_t c_int64; - uint64_t c_uint64; - } cint; - enum json_object_int_type cint_type; - } c_int; struct { union diff --git a/tests/test_double_serializer.c b/tests/test_double_serializer.c index 8b2487a..98f6dd9 100644 --- a/tests/test_double_serializer.c +++ b/tests/test_double_serializer.c @@ -20,7 +20,7 @@ int main() printf("obj.to_string(standard)=%s\n", json_object_to_json_string(obj)); printf("Test default serializer with custom userdata:\n"); - obj->_userdata = udata; + ((struct json_object_base *)obj)->_userdata = udata; printf("obj.to_string(userdata)=%s\n", json_object_to_json_string(obj)); printf("Test explicit serializer with custom userdata:\n"); From fe308b886248b1a5fa610b04c9871907f80de3d2 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 30 May 2020 19:36:54 +0000 Subject: [PATCH 17/94] Issue #626: Restore compatibility with cmake 2.8 by adjusting quoting and explicitly defining the PROJECT_VERSION* variables. --- CMakeLists.txt | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 333513c..b52255f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,15 @@ if(POLICY CMP0048) endif() # JSON-C library is C only project. -project(json-c LANGUAGES C VERSION 0.14.99) +if (CMAKE_VERSION VERSION_LESS 3.0) + project(json-c) + set(PROJECT_VERSION_MAJOR "0") + set(PROJECT_VERSION_MINOR "14") + set(PROJECT_VERSION_PATCH "99") + set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") +else() + project(json-c LANGUAGES C VERSION 0.14.99) +endif() # If we've got 3.0 then it's good, let's provide support. Otherwise, leave it be. if(POLICY CMP0038) @@ -207,11 +215,11 @@ check_type_size("long long" SIZEOF_LONG_LONG) check_type_size("size_t" SIZEOF_SIZE_T) check_c_source_compiles( -[=[ +" extern void json_object_get(); -__asm__(".section .gnu.json_object_get\\n\\t.ascii \\"Please link against libjson-c instead of libjson\\"\\n\\t.text"); +__asm__(\".section .gnu.json_object_get\\n\\t.ascii \\\"Please link against libjson-c instead of libjson\\\"\\n\\t.text\"); int main(int c, char *v) { return 0;} -]=] +" HAS_GNU_WARNING_LONG) check_c_source_compiles( @@ -270,7 +278,7 @@ endif() if (NOT ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")) check_c_source_compiles( - [=[ + " /* uClibc toolchains without threading barf when _REENTRANT is defined */ #define _REENTRANT 1 #include @@ -278,7 +286,7 @@ if (NOT ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")) { return 0; } - ]=] + " REENTRANT_WORKS ) if (REENTRANT_WORKS) @@ -289,12 +297,12 @@ if (NOT ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")) # Others may not support it, too. list(APPEND CMAKE_REQUIRED_LIBRARIES "-Wl,-Bsymbolic-functions") check_c_source_compiles( - [=[ + " int main (void) { return 0; } - ]=] + " BSYMBOLIC_WORKS ) list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "-Wl,-Bsymbolic-functions") From 1c6086a86aa26c643a0c9e8bc4a1f7d652b33662 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 31 May 2020 03:22:14 +0000 Subject: [PATCH 18/94] Apply the fix from @pointbre in issue #626 to skip "inline" on AIX, but invert the test to make it a little easier to understand. --- linkhash.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linkhash.h b/linkhash.h index 9377723..414599d 100644 --- a/linkhash.h +++ b/linkhash.h @@ -311,11 +311,11 @@ int lh_table_resize(struct lh_table *t, int new_size); /** * @deprecated Don't use this outside of linkhash.h: */ -#if !defined(_MSC_VER) || (_MSC_VER > 1800) +#if (defined(AIX_CC) || (defined(_MSC_VER) && (_MSC_VER <= 1800)) ) /* VS2010 can't handle inline funcs, so skip it there */ -#define _LH_INLINE inline -#else #define _LH_INLINE +#else +#define _LH_INLINE inline #endif /** From 481d0a8edec6b66e3c7a2ad6862ed09e66acf0fe Mon Sep 17 00:00:00 2001 From: Gianluigi Tiesi Date: Mon, 1 Jun 2020 20:49:08 +0200 Subject: [PATCH 19/94] get_cryptgenrandom_seed: compat with old windows + fallback --- random_seed.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/random_seed.c b/random_seed.c index b5f8a07..833b1a5 100644 --- a/random_seed.c +++ b/random_seed.c @@ -226,27 +226,35 @@ static int get_dev_random_seed(void) #pragma comment(lib, "advapi32.lib") #endif +static int get_time_seed(void); + static int get_cryptgenrandom_seed(void) { HCRYPTPROV hProvider = 0; + DWORD dwFlags = CRYPT_VERIFYCONTEXT; int r; DEBUG_SEED("get_cryptgenrandom_seed"); - if (!CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) - { - fprintf(stderr, "error CryptAcquireContextW"); - exit(1); - } + /* WinNT 4 and Win98 do no support CRYPT_SILENT */ + if (LOBYTE(LOWORD(GetVersion())) > 4) + dwFlags |= CRYPT_SILENT; - if (!CryptGenRandom(hProvider, sizeof(r), (BYTE *)&r)) + if (!CryptAcquireContextA(&hProvider, 0, 0, PROV_RSA_FULL, dwFlags)) { - fprintf(stderr, "error CryptGenRandom"); - exit(1); + fprintf(stderr, "error CryptAcquireContextA 0x%08lx", GetLastError()); + r = get_time_seed(); + } + else + { + BOOL ret = CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r); + CryptReleaseContext(hProvider, 0); + if (!ret) + { + fprintf(stderr, "error CryptGenRandom 0x%08lx", GetLastError()); + r = get_time_seed(); + } } - - CryptReleaseContext(hProvider, 0); return r; } From 0fc9d91277c24e7a9b8e2b0eeb4df16c2132ac2d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 02:42:58 +0000 Subject: [PATCH 20/94] Kick json_type_string out of struct json_object. The default is now that string data is stored inline at the end of json_object, though to allow for json_object_set_string() to set a _longer_ string, we still need to allow for the possibility of a separate char * pointer. All json types have been split out now, next step it cleanup. --- CMakeLists.txt | 1 + cmake/config.h.in | 3 + json_object.c | 247 +++++++++++++++++++++++++---------------- json_object_private.h | 30 ++--- tests/test_set_value.c | 4 + 5 files changed, 169 insertions(+), 116 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 333513c..16d1336 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,6 +205,7 @@ check_type_size(int64_t SIZEOF_INT64_T) check_type_size(long SIZEOF_LONG) check_type_size("long long" SIZEOF_LONG_LONG) check_type_size("size_t" SIZEOF_SIZE_T) +check_type_size("ssize_t" SIZEOF_SSIZE_T) check_c_source_compiles( [=[ diff --git a/cmake/config.h.in b/cmake/config.h.in index 456c26a..8b31164 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -194,6 +194,9 @@ /* The number of bytes in type size_t */ #cmakedefine SIZEOF_SIZE_T @SIZEOF_SIZE_T@ +/* The number of bytes in type ssize_t */ +#cmakedefine SIZEOF_SSIZE_T @SIZEOF_SSIZE_T@ + /* Specifier for __thread */ #cmakedefine SPEC___THREAD @SPEC___THREAD@ diff --git a/json_object.c b/json_object.c index 5300448..7069f5d 100644 --- a/json_object.c +++ b/json_object.c @@ -16,6 +16,9 @@ #include #include +#ifdef HAVE_LIMITS_H +#include +#endif #include #include #include @@ -38,6 +41,18 @@ #error "The long long type isn't 64-bits" #endif +#ifndef SSIZE_T_MAX +#if SIZEOF_SSIZE_T == SIZEOF_INT +#define SSIZE_T_MAX UINT_MAX +#elif SIZEOF_SSIZE_T == SIZEOF_LONG +#define SSIZE_T_MAX ULONG_MAX +#elif SIZEOF_SSIZE_T == SIZEOF_LONG_LONG +#define SSIZE_T_MAX ULLONG_MAX +#else +#error Unable to determine size of ssize_t +#endif +#endif + // Don't define this. It's not thread-safe. /* #define REFCOUNT_DEBUG 1 */ @@ -51,6 +66,8 @@ static struct json_object *json_object_new(enum json_type o_type); #if defined(_MSC_VER) && (_MSC_VER <= 1800) /* VS2013 doesn't know about "inline" */ #define inline __inline +#elif defined(AIX_CC) +#define inline #endif // XAX kill this once json_object_base is renamed back to json_object @@ -192,19 +209,23 @@ static void json_object_fini(void) /* helper for accessing the optimized string data component in json_object */ -// XAX drop this function -static const char *get_string_component(const struct json_object *jso) +static inline char *get_string_component_mutable(struct json_object_base *jso) { - if (jso->newold) - return ((const struct json_object_string *)jso)->data; - return (jso->o.c_string.len < LEN_DIRECT_STRING_DATA) ? jso->o.c_string.str.data - : jso->o.c_string.str.ptr; - + if (JC_STRING_C(jso)->len < 0) + { + /* Due to json_object_str_string(), we might have a pointer */ + return JC_STRING(jso)->c_string.pdata; + } + return JC_STRING(jso)->c_string.idata; +} +static inline const char *get_string_component(const struct json_object_base *jso) +{ + return get_string_component_mutable((void *)(uintptr_t)(const void *)jso); } /* string escaping */ -static int json_escape_str(struct printbuf *pb, const char *str, int len, int flags) +static int json_escape_str(struct printbuf *pb, const char *str, size_t len, int flags) { int pos = 0, start_offset = 0; unsigned char c; @@ -836,10 +857,10 @@ json_bool json_object_get_boolean(const struct json_object *jso) default: json_abort("invalid cint_type"); } case json_type_double: return (JC_DOUBLE_C(jso)->c_double != 0); -#undef jso - case json_type_string: return (jso->o.c_string.len != 0); + case json_type_string: return (JC_STRING_C(jso)->len != 0); default: return 0; } +#undef jso } int json_object_set_boolean(struct json_object *jso, json_bool new_value) @@ -905,7 +926,7 @@ int32_t json_object_get_int(const struct json_object *jso) * Parse strings into 64-bit numbers, then use the * 64-to-32-bit number handling below. */ - if (json_parse_int64(get_string_component(PUBLIC_C(jso)), &cint64) != 0) + if (json_parse_int64(get_string_component(jso), &cint64) != 0) return 0; /* whoops, it didn't work. */ o_type = json_type_int; } @@ -989,7 +1010,7 @@ int64_t json_object_get_int64(const struct json_object *jso) return (int64_t)JC_DOUBLE_C(jso)->c_double; case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; case json_type_string: - if (json_parse_int64(get_string_component(PUBLIC_C(jso)), &cint) == 0) + if (json_parse_int64(get_string_component(jso), &cint) == 0) return cint; /* FALLTHRU */ default: return 0; @@ -1029,7 +1050,7 @@ uint64_t json_object_get_uint64(const struct json_object *jso) return (uint64_t)JC_DOUBLE_C(jso)->c_double; case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; case json_type_string: - if (json_parse_uint64(get_string_component(PUBLIC_C(jso)), &cuint) == 0) + if (json_parse_uint64(get_string_component(jso), &cuint) == 0) return cuint; /* FALLTHRU */ default: return 0; @@ -1353,10 +1374,10 @@ double json_object_get_double(const struct json_object *jso) case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; case json_type_string: errno = 0; - cdouble = strtod(get_string_component(PUBLIC_C(jso)), &errPtr); + cdouble = strtod(get_string_component(jso), &errPtr); /* if conversion stopped at the first character, return 0.0 */ - if (errPtr == get_string_component(PUBLIC_C(jso))) + if (errPtr == get_string_component(jso)) { errno = EINVAL; return 0.0; @@ -1409,124 +1430,154 @@ int json_object_set_double(struct json_object *jso, double new_value) static int json_object_string_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { +#define jso ((struct json_object_base *)jso) printbuf_strappend(pb, "\""); - json_escape_str(pb, get_string_component(jso), jso->o.c_string.len, flags); + ssize_t len = JC_STRING(jso)->len; + json_escape_str(pb, get_string_component(jso), len < 0 ? -len : len, flags); printbuf_strappend(pb, "\""); return 0; +#undef jso } static void json_object_string_delete(struct json_object *jso) { - if (jso->o.c_string.len >= LEN_DIRECT_STRING_DATA) - free(jso->o.c_string.str.ptr); - json_object_generic_delete(jso); +#define jso ((struct json_object_base *)jso) + if (JC_STRING(jso)->len < 0) + free(JC_STRING(jso)->c_string.pdata); + Xjson_object_generic_delete(jso); +#undef jso +} + +static struct json_object *_json_object_new_string(const char *s, const size_t len) +{ + size_t objsize; + struct json_object_string *jso; + + /* + * Structures Actual memory layout + * ------------------- -------------------- + * [json_object_string [json_object_string + * [json_object_base] [json_object_base] + * ...other fields... ...other fields... + * c_string] len + * bytes + * of + * string + * data + * \0] + */ + if (len > (SSIZE_T_MAX - (sizeof(*jso) - sizeof(jso->c_string)) - 1)) + return NULL; + objsize = (sizeof(*jso) - sizeof(jso->c_string)) + len + 1; + if (len < sizeof(void *)) + // We need a minimum size to support json_object_set_string() mutability + // so we can stuff a pointer into pdata :( + objsize += sizeof(void *) - len; + + jso = (struct json_object_string *)Xjson_object_new(json_type_string, objsize, + &json_object_string_to_json_string, &json_object_string_delete); + + if (!jso) + return NULL; + jso->len = len; + memcpy(jso->c_string.idata, s, len); + jso->c_string.idata[len] = '\0'; + return PUBLIC(&jso->base); } struct json_object *json_object_new_string(const char *s) { - struct json_object *jso = json_object_new(json_type_string); - if (!jso) - return NULL; - jso->_delete = &json_object_string_delete; - jso->_to_json_string = &json_object_string_to_json_string; - jso->o.c_string.len = strlen(s); - if (jso->o.c_string.len < LEN_DIRECT_STRING_DATA) - { - memcpy(jso->o.c_string.str.data, s, jso->o.c_string.len); - } - else - { - jso->o.c_string.str.ptr = strdup(s); - if (!jso->o.c_string.str.ptr) - { - json_object_generic_delete(jso); - errno = ENOMEM; - return NULL; - } - } - return jso; + return _json_object_new_string(s, strlen(s)); } struct json_object *json_object_new_string_len(const char *s, const int len) { - char *dstbuf; - struct json_object *jso = json_object_new(json_type_string); - if (!jso) - return NULL; - jso->_delete = &json_object_string_delete; - jso->_to_json_string = &json_object_string_to_json_string; - if (len < LEN_DIRECT_STRING_DATA) - { - dstbuf = jso->o.c_string.str.data; - } - else - { - jso->o.c_string.str.ptr = (char *)malloc(len + 1); - if (!jso->o.c_string.str.ptr) - { - json_object_generic_delete(jso); - errno = ENOMEM; - return NULL; - } - dstbuf = jso->o.c_string.str.ptr; - } - memcpy(dstbuf, (const void *)s, len); - dstbuf[len] = '\0'; - jso->o.c_string.len = len; - return jso; + return _json_object_new_string(s, len); } const char *json_object_get_string(struct json_object *jso) { +#define jso ((struct json_object_base *)jso) if (!jso) return NULL; switch (jso->o_type) { case json_type_string: return get_string_component(jso); - default: return json_object_to_json_string(jso); + default: return json_object_to_json_string(PUBLIC(jso)); } +#undef jso } - int json_object_get_string_len(const struct json_object *jso) { +#define jso ((const struct json_object_base *)jso) + ssize_t len; if (!jso) return 0; switch (jso->o_type) { - case json_type_string: return jso->o.c_string.len; + case json_type_string: + len = JC_STRING_C(jso)->len; + return (len < 0) ? -len : len; default: return 0; } +#undef jso +} + +static int _json_object_set_string_len(json_object *jso, const char *s, size_t len) +{ +#define jso ((struct json_object_base *)jso) + char *dstbuf; + ssize_t curlen; + ssize_t newlen; + if (jso == NULL || jso->o_type != json_type_string) + return 0; + + if (len >= SSIZE_T_MAX - 1) + // jso->len is a signed ssize_t, so it can't hold the + // full size_t range. + return 0; + + dstbuf = get_string_component_mutable(jso); + curlen = JC_STRING(jso)->len; + if (curlen < 0) + curlen = -curlen; + newlen = len; + + if ((ssize_t)len > curlen) + { + // We have no way to return the new ptr from realloc(jso, newlen) + // and we have no way of knowing whether there's extra room available + // so we need to stuff a pointer in to pdata :( + dstbuf = (char *)malloc(len + 1); + if (dstbuf == NULL) + return 0; + if (JC_STRING(jso)->len < 0) + free(JC_STRING(jso)->c_string.pdata); + JC_STRING(jso)->c_string.pdata = dstbuf; + newlen = -len; + } + else if (JC_STRING(jso)->len < 0) + { + // We've got enough room in the separate allocated buffer, + // so use it as-is and continue to indicate that pdata is used. + newlen = -len; + } + + memcpy(dstbuf, (const void *)s, len); + dstbuf[len] = '\0'; + JC_STRING(jso)->len = newlen; + return 1; +#undef jso } int json_object_set_string(json_object *jso, const char *s) { - return json_object_set_string_len(jso, s, (int)(strlen(s))); + return _json_object_set_string_len(jso, s, strlen(s)); } int json_object_set_string_len(json_object *jso, const char *s, int len) { - char *dstbuf; - if (jso == NULL || jso->o_type != json_type_string) - return 0; - if (len < LEN_DIRECT_STRING_DATA) - { - dstbuf = jso->o.c_string.str.data; - if (jso->o.c_string.len >= LEN_DIRECT_STRING_DATA) - free(jso->o.c_string.str.ptr); - } - else - { - dstbuf = (char *)malloc(len + 1); - if (dstbuf == NULL) - return 0; - if (jso->o.c_string.len >= LEN_DIRECT_STRING_DATA) - free(jso->o.c_string.str.ptr); - jso->o.c_string.str.ptr = dstbuf; - } - jso->o.c_string.len = len; - memcpy(dstbuf, (const void *)s, len); - dstbuf[len] = '\0'; - return 1; + return _json_object_set_string_len(jso, s, len); } /* json_object_array */ @@ -1582,7 +1633,7 @@ static void json_object_array_delete(struct json_object *jso) { #define jso ((struct json_object_base *)jso) array_list_free(JC_ARRAY(jso)->c_array); - json_object_generic_delete(PUBLIC(jso)); + Xjson_object_generic_delete(jso); #undef jso } @@ -1762,10 +1813,12 @@ static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2 return (jso1->o.c_int.cint.c_uint64 == (uint64_t)jso2->o.c_int.cint.c_int64); */ - case json_type_string: + case json_type_string: assert(0); + /* return (jso1->o.c_string.len == jso2->o.c_string.len && memcmp(get_string_component(jso1), get_string_component(jso2), jso1->o.c_string.len) == 0); + */ case json_type_object: assert(0); //return json_object_all_values_equal(jso1, jso2); @@ -1822,10 +1875,8 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) case json_type_string: { - struct json_object_string *str1 = JC_STRING(jso1); - struct json_object_string *str2 = JC_STRING(jso2); - return (str1->len == str2->len && - memcmp(str1->data, str2->data, str1->len) == 0); + return (json_object_get_string_len(PUBLIC(jso1)) == json_object_get_string_len(PUBLIC(jso2)) && + memcmp(get_string_component(jso1), get_string_component(jso2), json_object_get_string_len(PUBLIC(jso1))) == 0); } case json_type_object: return json_object_all_values_equal(jso1, jso2); @@ -1920,7 +1971,6 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha default: json_abort("invalid cint_type"); } break; -#undef src case json_type_string: *dst = json_object_new_string(get_string_component(src)); break; @@ -1939,6 +1989,7 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha (*dst)->_to_json_string = src->_to_json_string; // _userdata and _user_delete are copied later return 1; +#undef src } /* diff --git a/json_object_private.h b/json_object_private.h index 5ea865c..bfe2b1c 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -46,7 +46,7 @@ struct json_object_base // XAX rename to json_object after conversion struct printbuf *_pb; json_object_delete_fn *_user_delete; void *_userdata; - char data[1]; // Actually a struct json_object_${o_type} + char data[1]; // Actually the rest of a struct json_object_${o_type} }; struct json_object_object @@ -83,8 +83,14 @@ struct json_object_int struct json_object_string { struct json_object_base base; - size_t len; - char data[1]; // Actually longer + ssize_t len; // Signed b/c negative lengths indicate data is a pointer + // Consider adding an "alloc" field here, if json_object_set_string calls + // to expand the length of a string are common operations to perform. + union + { + char idata[1]; // Immediate data. Actually longer + char *pdata; // Only when len < 0 + } c_string; }; struct json_object @@ -95,21 +101,9 @@ struct json_object json_object_private_delete_fn *_delete; json_object_to_json_string_fn *_to_json_string; struct printbuf *_pb; - union data - { - struct - { - union - { - /* optimize: if we have small strings, we can store them - * directly. This saves considerable CPU cycles AND memory. - */ - char *ptr; - char data[LEN_DIRECT_STRING_DATA]; - } str; - int len; - } c_string; - } o; + int dummyval; // XAX temp spacer to catch casting errors + int du1mmyval; // XAX spacer + int d2ummyval; // XAX spacer json_object_delete_fn *_user_delete; void *_userdata; }; diff --git a/tests/test_set_value.c b/tests/test_set_value.c index d6f1a33..eb0fe8b 100644 --- a/tests/test_set_value.c +++ b/tests/test_set_value.c @@ -58,12 +58,16 @@ int main(int argc, char **argv) #define HUGE "A string longer than 32 chars as to check non local buf codepath" tmp = json_object_new_string(SHORT); assert(strcmp(json_object_get_string(tmp), SHORT) == 0); + assert(strcmp(json_object_to_json_string(tmp), "\"" SHORT "\"") == 0); json_object_set_string(tmp, MID); assert(strcmp(json_object_get_string(tmp), MID) == 0); + assert(strcmp(json_object_to_json_string(tmp), "\"" MID "\"") == 0); json_object_set_string(tmp, HUGE); assert(strcmp(json_object_get_string(tmp), HUGE) == 0); + assert(strcmp(json_object_to_json_string(tmp), "\"" HUGE "\"") == 0); json_object_set_string(tmp, SHORT); assert(strcmp(json_object_get_string(tmp), SHORT) == 0); + assert(strcmp(json_object_to_json_string(tmp), "\"" SHORT "\"") == 0); json_object_put(tmp); printf("STRING PASSED\n"); From b0466b626be8075280ac69b6d63fe747955357e0 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 03:27:13 +0000 Subject: [PATCH 21/94] On MSVC, add a ssize_t typedef using SSIZE_T from BaseTsd.h --- json_inttypes.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/json_inttypes.h b/json_inttypes.h index e047d4f..e51da74 100644 --- a/json_inttypes.h +++ b/json_inttypes.h @@ -21,4 +21,9 @@ #endif +#ifdef _MSC_VER +#include +typedef SSIZE_T ssize_t; +#endif + #endif From eab1375123d0ae1344dcfbfa80c6913b72803a13 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 03:36:59 +0000 Subject: [PATCH 22/94] Change CMakeLists.txt to look for SSIZE_T on MSVC too. --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 16d1336..1c0dd85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,7 +205,12 @@ check_type_size(int64_t SIZEOF_INT64_T) check_type_size(long SIZEOF_LONG) check_type_size("long long" SIZEOF_LONG_LONG) check_type_size("size_t" SIZEOF_SIZE_T) +if ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") +list(APPEND CMAKE_EXTRA_INCLUDE_FILES BaseTsd.h) +check_type_size("SSIZE_T" SIZEOF_SIZE_T) +else() check_type_size("ssize_t" SIZEOF_SSIZE_T) +endif() check_c_source_compiles( [=[ From 0a16b23adf7de1222c91ba10277fdbd2e889b144 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 15:19:29 +0000 Subject: [PATCH 23/94] Fix typo in previous commit to check for SSIZE_T on MSVC. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c0dd85..50a6770 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,9 +205,9 @@ check_type_size(int64_t SIZEOF_INT64_T) check_type_size(long SIZEOF_LONG) check_type_size("long long" SIZEOF_LONG_LONG) check_type_size("size_t" SIZEOF_SIZE_T) -if ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC") +if (MSVC) list(APPEND CMAKE_EXTRA_INCLUDE_FILES BaseTsd.h) -check_type_size("SSIZE_T" SIZEOF_SIZE_T) +check_type_size("SSIZE_T" SIZEOF_SSIZE_T) else() check_type_size("ssize_t" SIZEOF_SSIZE_T) endif() From c4cc6730715bd75d9776c6fe800e64bfacec510f Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 15:25:59 +0000 Subject: [PATCH 24/94] More fixes for old MSVC builds. --- json_object.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/json_object.c b/json_object.c index 7069f5d..dfe7bb2 100644 --- a/json_object.c +++ b/json_object.c @@ -1431,9 +1431,9 @@ static int json_object_string_to_json_string(struct json_object *jso, struct pri int level, int flags) { #define jso ((struct json_object_base *)jso) - printbuf_strappend(pb, "\""); ssize_t len = JC_STRING(jso)->len; - json_escape_str(pb, get_string_component(jso), len < 0 ? -len : len, flags); + printbuf_strappend(pb, "\""); + json_escape_str(pb, get_string_component(jso), len < 0 ? -(ssize_t)len : len, flags); printbuf_strappend(pb, "\""); return 0; #undef jso @@ -1517,7 +1517,7 @@ int json_object_get_string_len(const struct json_object *jso) { case json_type_string: len = JC_STRING_C(jso)->len; - return (len < 0) ? -len : len; + return (len < 0) ? -(ssize_t)len : len; default: return 0; } #undef jso @@ -1554,13 +1554,13 @@ static int _json_object_set_string_len(json_object *jso, const char *s, size_t l if (JC_STRING(jso)->len < 0) free(JC_STRING(jso)->c_string.pdata); JC_STRING(jso)->c_string.pdata = dstbuf; - newlen = -len; + newlen = -(ssize_t)len; } else if (JC_STRING(jso)->len < 0) { // We've got enough room in the separate allocated buffer, // so use it as-is and continue to indicate that pdata is used. - newlen = -len; + newlen = -(ssize_t)len; } memcpy(dstbuf, (const void *)s, len); From 66d91fdf86bb650201da37e704c29c197a1dadd9 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 03:30:39 +0000 Subject: [PATCH 25/94] The split of json_object into type-specific sub-structures is now functionally complete. Remove all of the temporary defines, structures, old compat fuctions, extra fields, etc... that were needed during the conversion to a split set of json_object_* structures. --- json_object.c | 474 ++++++--------------------------- json_object.h | 3 +- json_object_private.h | 35 +-- tests/test_double_serializer.c | 2 +- tests/test_set_value.c | 8 +- 5 files changed, 89 insertions(+), 433 deletions(-) diff --git a/json_object.c b/json_object.c index dfe7bb2..bed97cd 100644 --- a/json_object.c +++ b/json_object.c @@ -1,6 +1,4 @@ /* - * $Id: json_object.c,v 1.17 2006/07/25 03:24:50 mclark Exp $ - * * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. * Michael Clark * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. @@ -60,8 +58,6 @@ const char *json_number_chars = "0123456789.+-eE"; const char *json_hex_chars = "0123456789abcdefABCDEF"; static void json_object_generic_delete(struct json_object *jso); -static void Xjson_object_generic_delete(struct json_object_base *jso); -static struct json_object *json_object_new(enum json_type o_type); #if defined(_MSC_VER) && (_MSC_VER <= 1800) /* VS2013 doesn't know about "inline" */ @@ -70,64 +66,54 @@ static struct json_object *json_object_new(enum json_type o_type); #define inline #endif -// XAX kill this once json_object_base is renamed back to json_object -static inline struct json_object *PUBLIC(struct json_object_base *jso) -{ - return (struct json_object *)jso; -} -static inline const struct json_object *PUBLIC_C(const struct json_object_base *jso) -{ - return (const struct json_object *)jso; -} - /* * Helper functions to more safely cast to a particular type of json_object */ -static inline struct json_object_object *JC_OBJECT(struct json_object_base *jso) +static inline struct json_object_object *JC_OBJECT(struct json_object *jso) { return (void *)jso; } -static inline const struct json_object_object *JC_OBJECT_C(const struct json_object_base *jso) +static inline const struct json_object_object *JC_OBJECT_C(const struct json_object *jso) { return (const void *)jso; } -static inline struct json_object_array *JC_ARRAY(struct json_object_base *jso) +static inline struct json_object_array *JC_ARRAY(struct json_object *jso) { return (void *)jso; } -static inline const struct json_object_array *JC_ARRAY_C(const struct json_object_base *jso) +static inline const struct json_object_array *JC_ARRAY_C(const struct json_object *jso) { return (const void *)jso; } -static inline struct json_object_boolean *JC_BOOL(struct json_object_base *jso) +static inline struct json_object_boolean *JC_BOOL(struct json_object *jso) { return (void *)jso; } -static inline const struct json_object_boolean *JC_BOOL_C(const struct json_object_base *jso) +static inline const struct json_object_boolean *JC_BOOL_C(const struct json_object *jso) { return (const void *)jso; } -static inline struct json_object_double *JC_DOUBLE(struct json_object_base *jso) +static inline struct json_object_double *JC_DOUBLE(struct json_object *jso) { return (void *)jso; } -static inline const struct json_object_double *JC_DOUBLE_C(const struct json_object_base *jso) +static inline const struct json_object_double *JC_DOUBLE_C(const struct json_object *jso) { return (const void *)jso; } -static inline struct json_object_int *JC_INT(struct json_object_base *jso) +static inline struct json_object_int *JC_INT(struct json_object *jso) { return (void *)jso; } -static inline const struct json_object_int *JC_INT_C(const struct json_object_base *jso) +static inline const struct json_object_int *JC_INT_C(const struct json_object *jso) { return (const void *)jso; } -static inline struct json_object_string *JC_STRING(struct json_object_base *jso) +static inline struct json_object_string *JC_STRING(struct json_object *jso) { return (void *)jso; } -static inline const struct json_object_string *JC_STRING_C(const struct json_object_base *jso) +static inline const struct json_object_string *JC_STRING_C(const struct json_object *jso) { return (const void *)jso; } @@ -136,11 +122,11 @@ static inline const struct json_object_string *JC_STRING_C(const struct json_obj #define JC_CONCAT3(a,b,c) a##b##c #define JSON_OBJECT_NEW(jtype, delete_fn) \ - (struct JC_CONCAT(json_object_,jtype) *)Xjson_object_new(JC_CONCAT(json_type_,jtype), \ + (struct JC_CONCAT(json_object_,jtype) *)json_object_new(JC_CONCAT(json_type_,jtype), \ sizeof(struct JC_CONCAT(json_object_,jtype)), \ &JC_CONCAT3(json_object_,jtype,_to_json_string), \ - (void *)delete_fn) // XAX drop cast -static inline struct json_object_base *Xjson_object_new(enum json_type o_type, + delete_fn) +static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, json_object_to_json_string_fn *to_json_string, json_object_private_delete_fn *delete_fn); @@ -209,7 +195,7 @@ static void json_object_fini(void) /* helper for accessing the optimized string data component in json_object */ -static inline char *get_string_component_mutable(struct json_object_base *jso) +static inline char *get_string_component_mutable(struct json_object *jso) { if (JC_STRING_C(jso)->len < 0) { @@ -218,7 +204,7 @@ static inline char *get_string_component_mutable(struct json_object_base *jso) } return JC_STRING(jso)->c_string.idata; } -static inline const char *get_string_component(const struct json_object_base *jso) +static inline const char *get_string_component(const struct json_object *jso) { return get_string_component_mutable((void *)(uintptr_t)(const void *)jso); } @@ -310,42 +296,10 @@ struct json_object *json_object_get(struct json_object *jso) return jso; } -// XAX remove this Xjson_object_put function once conversion is done -static int Xjson_object_put(struct json_object_base *jso) -{ - if (!jso) - return 0; - - /* Avoid invalid free and crash explicitly instead of (silently) - * segfaulting. - */ - assert(jso->_ref_count > 0); - -#if defined(HAVE_ATOMIC_BUILTINS) && defined(ENABLE_THREADING) - /* Note: this only allow the refcount to remain correct - * when multiple threads are adjusting it. It is still an error - * for a thread to decrement the refcount if it doesn't "own" it, - * as that can result in the thread that loses the race to 0 - * operating on an already-freed object. - */ - if (__sync_sub_and_fetch(&jso->_ref_count, 1) > 0) - return 0; -#else - if (--jso->_ref_count > 0) - return 0; -#endif - - if (jso->_user_delete) - jso->_user_delete(PUBLIC(jso), jso->_userdata); - jso->_delete(PUBLIC(jso)); - return 1; -} int json_object_put(struct json_object *jso) { if (!jso) return 0; - if (jso->newold) - return Xjson_object_put((struct json_object_base *)jso); /* Avoid invalid free and crash explicitly instead of (silently) * segfaulting. @@ -376,10 +330,6 @@ int json_object_put(struct json_object *jso) /* generic object construction and destruction parts */ static void json_object_generic_delete(struct json_object *jso) -{ - Xjson_object_generic_delete((void *)jso); -} -static void Xjson_object_generic_delete(struct json_object_base *jso) { #ifdef REFCOUNT_DEBUG MC_DEBUG("json_object_delete_%s: %p\n", json_type_to_name(jso->o_type), jso); @@ -389,37 +339,17 @@ static void Xjson_object_generic_delete(struct json_object_base *jso) free(jso); } -// XAX remove this once all is using new api -static inline struct json_object *json_object_new(enum json_type o_type) -{ - struct json_object *jso; - - jso = (struct json_object *)calloc(1, sizeof(struct json_object)); - if (!jso) - return NULL; - jso->o_type = o_type; - jso->_ref_count = 1; - jso->_delete = &json_object_generic_delete; - -#ifdef REFCOUNT_DEBUG - lh_table_insert(json_object_table, jso, jso); - MC_DEBUG("json_object_new_%s: %p\n", json_type_to_name(jso->o_type), jso); -#endif /* REFCOUNT_DEBUG */ - return jso; -} - -static inline struct json_object_base *Xjson_object_new(enum json_type o_type, +static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, json_object_to_json_string_fn *to_json_string, json_object_private_delete_fn *delete_fn) { - struct json_object_base *jso; + struct json_object *jso; - jso = (struct json_object_base *)malloc(alloc_size); + jso = (struct json_object *)malloc(alloc_size); if (!jso) return NULL; - jso->newold = 1; // XAX cut this after conversion jso->o_type = o_type; jso->_ref_count = 1; jso->_delete = delete_fn; @@ -440,32 +370,24 @@ static inline struct json_object_base *Xjson_object_new(enum json_type o_type, int json_object_is_type(const struct json_object *jso, enum json_type type) { -#define jso ((const struct json_object_base *)jso) if (!jso) return (type == json_type_null); return (jso->o_type == type); -#undef jso } enum json_type json_object_get_type(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) if (!jso) return json_type_null; return jso->o_type; -#undef jso } void *json_object_get_userdata(json_object *jso) { - if (!jso->newold) - return jso ? jso->_userdata : NULL; -#define jso ((const struct json_object_base *)jso) return jso ? jso->_userdata : NULL; -#undef jso } -static void Xjson_object_set_userdata(json_object *jso, void *userdata, json_object_delete_fn *user_delete) +void json_object_set_userdata(json_object *jso, void *userdata, json_object_delete_fn *user_delete) { // Can't return failure, so abort if we can't perform the operation. assert(jso != NULL); @@ -477,30 +399,10 @@ static void Xjson_object_set_userdata(json_object *jso, void *userdata, json_obj jso->_userdata = userdata; jso->_user_delete = user_delete; } -void json_object_set_userdata(json_object *jso, void *userdata, json_object_delete_fn *user_delete) -{ - // XAX call old code: - if (!jso->newold) - { - Xjson_object_set_userdata(jso, userdata, user_delete); - return; - } -#define jso ((struct json_object_base *)jso) - // Can't return failure, so abort if we can't perform the operation. - assert(jso != NULL); - - // First, clean up any previously existing user info - if (jso->_user_delete) - jso->_user_delete(PUBLIC(jso), jso->_userdata); - - jso->_userdata = userdata; - jso->_user_delete = user_delete; -#undef jso -} /* set a custom conversion to string */ -static void Xjson_object_set_serializer(json_object *jso, json_object_to_json_string_fn *to_string_func, +void json_object_set_serializer(json_object *jso, json_object_to_json_string_fn *to_string_func, void *userdata, json_object_delete_fn *user_delete) { json_object_set_userdata(jso, userdata, user_delete); @@ -534,53 +436,10 @@ static void Xjson_object_set_serializer(json_object *jso, json_object_to_json_st jso->_to_json_string = to_string_func; } -void json_object_set_serializer(json_object *jso, json_object_to_json_string_fn *to_string_func, - void *userdata, json_object_delete_fn *user_delete) -{ - // XAX call old code, remove after conversion: - if (jso && !jso->newold) - { - Xjson_object_set_serializer(jso, to_string_func, userdata, user_delete); - return; - } -#define jso ((struct json_object_base *)jso) - json_object_set_userdata(PUBLIC(jso), userdata, user_delete); - - if (to_string_func == NULL) - { - // Reset to the standard serialization function - switch (jso->o_type) - { - case json_type_null: jso->_to_json_string = NULL; break; - case json_type_boolean: - jso->_to_json_string = &json_object_boolean_to_json_string; - break; - case json_type_double: - jso->_to_json_string = &json_object_double_to_json_string_default; - break; - case json_type_int: jso->_to_json_string = &json_object_int_to_json_string; break; - case json_type_object: - jso->_to_json_string = &json_object_object_to_json_string; - break; - case json_type_array: - jso->_to_json_string = &json_object_array_to_json_string; - break; - case json_type_string: - jso->_to_json_string = &json_object_string_to_json_string; - break; - } - return; - } - - jso->_to_json_string = to_string_func; -#undef jso -} - /* extended conversion to string */ const char *json_object_to_json_string_length(struct json_object *jso, int flags, size_t *length) { -#define jso ((struct json_object_base *)jso) const char *r = NULL; size_t s = 0; @@ -593,7 +452,7 @@ const char *json_object_to_json_string_length(struct json_object *jso, int flags { printbuf_reset(jso->_pb); - if (jso->_to_json_string(PUBLIC(jso), jso->_pb, 0, flags) >= 0) + if (jso->_to_json_string(jso, jso->_pb, 0, flags) >= 0) { s = (size_t)jso->_pb->bpos; r = jso->_pb->buf; @@ -603,7 +462,6 @@ const char *json_object_to_json_string_length(struct json_object *jso, int flags if (length) *length = s; return r; -#undef jso } const char *json_object_to_json_string_ext(struct json_object *jso, int flags) @@ -638,7 +496,6 @@ static void indent(struct printbuf *pb, int level, int flags) static int json_object_object_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) int had_children = 0; struct json_object_iter iter; @@ -678,7 +535,6 @@ static int json_object_object_to_json_string(struct json_object *jso, struct pri return printbuf_strappend(pb, /*{*/ " }"); else return printbuf_strappend(pb, /*{*/ "}"); -#undef jso } static void json_object_lh_entry_free(struct lh_entry *ent) @@ -688,10 +544,10 @@ static void json_object_lh_entry_free(struct lh_entry *ent) json_object_put((struct json_object *)lh_entry_v(ent)); } -static void json_object_object_delete(struct json_object_base *jso_base) +static void json_object_object_delete(struct json_object *jso_base) { lh_table_free(JC_OBJECT(jso_base)->c_object); - Xjson_object_generic_delete(jso_base); + json_object_generic_delete(jso_base); } struct json_object *json_object_new_object(void) @@ -703,16 +559,15 @@ struct json_object *json_object_new_object(void) lh_kchar_table_new(JSON_OBJECT_DEF_HASH_ENTRIES, &json_object_lh_entry_free); if (!jso->c_object) { - Xjson_object_generic_delete(&jso->base); + json_object_generic_delete(&jso->base); errno = ENOMEM; return NULL; } - return PUBLIC(&jso->base); + return &jso->base; } struct lh_table *json_object_get_object(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) if (!jso) return NULL; switch (jso->o_type) @@ -720,19 +575,16 @@ struct lh_table *json_object_get_object(const struct json_object *jso) case json_type_object: return JC_OBJECT_C(jso)->c_object; default: return NULL; } -#undef jso } int json_object_object_add_ex(struct json_object *jso, const char *const key, struct json_object *const val, const unsigned opts) { -#define jso ((struct json_object_base *)jso) -#define val ((struct json_object_base *)val) struct json_object *existing_value = NULL; struct lh_entry *existing_entry; unsigned long hash; - assert(json_object_get_type(PUBLIC(jso)) == json_type_object); + assert(json_object_get_type(jso) == json_type_object); // We lookup the entry and replace the value, rather than just deleting // and re-adding it, so the existing key remains valid. @@ -760,8 +612,6 @@ int json_object_object_add_ex(struct json_object *jso, const char *const key, json_object_put(existing_value); existing_entry->v = val; return 0; -#undef jso -#undef val } int json_object_object_add(struct json_object *jso, const char *key, struct json_object *val) @@ -771,10 +621,8 @@ int json_object_object_add(struct json_object *jso, const char *key, struct json int json_object_object_length(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_object); + assert(json_object_get_type(jso) == json_type_object); return lh_table_length(JC_OBJECT_C(jso)->c_object); -#undef jso } @@ -793,7 +641,6 @@ struct json_object *json_object_object_get(const struct json_object *jso, const json_bool json_object_object_get_ex(const struct json_object *jso, const char *key, struct json_object **value) { -#define jso ((const struct json_object_base *)jso) if (value != NULL) *value = NULL; @@ -809,15 +656,12 @@ json_bool json_object_object_get_ex(const struct json_object *jso, const char *k *value = NULL; return 0; } -#undef jso } void json_object_object_del(struct json_object *jso, const char *key) { -#define jso ((struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC(jso)) == json_type_object); + assert(json_object_get_type(jso) == json_type_object); lh_table_delete(JC_OBJECT(jso)->c_object, key); -#undef jso } /* json_object_boolean */ @@ -825,11 +669,9 @@ void json_object_object_del(struct json_object *jso, const char *key) static int json_object_boolean_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) if (JC_BOOL(jso)->c_boolean) return printbuf_strappend(pb, "true"); return printbuf_strappend(pb, "false"); -#undef jso } struct json_object *json_object_new_boolean(json_bool b) @@ -838,7 +680,7 @@ struct json_object *json_object_new_boolean(json_bool b) if (!jso) return NULL; jso->c_boolean = b; - return PUBLIC(&jso->base); + return &jso->base; } json_bool json_object_get_boolean(const struct json_object *jso) @@ -847,7 +689,6 @@ json_bool json_object_get_boolean(const struct json_object *jso) return 0; switch (jso->o_type) { -#define jso ((const struct json_object_base *)jso) case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; case json_type_int: switch (JC_INT_C(jso)->cint_type) @@ -860,17 +701,14 @@ json_bool json_object_get_boolean(const struct json_object *jso) case json_type_string: return (JC_STRING_C(jso)->len != 0); default: return 0; } -#undef jso } int json_object_set_boolean(struct json_object *jso, json_bool new_value) { -#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_boolean) return 0; JC_BOOL(jso)->c_boolean = new_value; return 1; -#undef jso } /* json_object_int */ @@ -878,7 +716,6 @@ int json_object_set_boolean(struct json_object *jso, json_bool new_value) static int json_object_int_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) /* room for 19 digits, the sign char, and a null term */ char sbuf[21]; if (JC_INT(jso)->cint_type == json_object_int_type_int64) @@ -886,7 +723,6 @@ static int json_object_int_to_json_string(struct json_object *jso, struct printb else snprintf(sbuf, sizeof(sbuf), "%" PRIu64, JC_INT(jso)->cint.c_uint64); return printbuf_memappend(pb, sbuf, strlen(sbuf)); -#undef jso } struct json_object *json_object_new_int(int32_t i) @@ -896,7 +732,6 @@ struct json_object *json_object_new_int(int32_t i) int32_t json_object_get_int(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) int64_t cint64; double cdouble; enum json_type o_type; @@ -950,7 +785,6 @@ int32_t json_object_get_int(const struct json_object *jso) case json_type_boolean: return JC_BOOL_C(jso)->c_boolean; default: return 0; } -#undef jso } int json_object_set_int(struct json_object *jso, int new_value) @@ -965,7 +799,7 @@ struct json_object *json_object_new_int64(int64_t i) return NULL; jso->cint.c_int64 = i; jso->cint_type = json_object_int_type_int64; - return PUBLIC(&jso->base); + return &jso->base; } struct json_object *json_object_new_uint64(uint64_t i) @@ -975,12 +809,11 @@ struct json_object *json_object_new_uint64(uint64_t i) return NULL; jso->cint.c_uint64 = i; jso->cint_type = json_object_int_type_uint64; - return PUBLIC(&jso->base); + return &jso->base; } int64_t json_object_get_int64(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) int64_t cint; if (!jso) @@ -1015,12 +848,10 @@ int64_t json_object_get_int64(const struct json_object *jso) /* FALLTHRU */ default: return 0; } -#undef jso } uint64_t json_object_get_uint64(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) uint64_t cuint; if (!jso) @@ -1055,34 +886,28 @@ uint64_t json_object_get_uint64(const struct json_object *jso) /* FALLTHRU */ default: return 0; } -#undef jso } int json_object_set_int64(struct json_object *jso, int64_t new_value) { -#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_int) return 0; JC_INT(jso)->cint.c_int64 = new_value; JC_INT(jso)->cint_type = json_object_int_type_int64; return 1; -#undef jso } int json_object_set_uint64(struct json_object *jso, uint64_t new_value) { -#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_int) return 0; JC_INT(jso)->cint.c_uint64 = new_value; JC_INT(jso)->cint_type = json_object_int_type_uint64; return 1; -#undef jso } int json_object_int_inc(struct json_object *jso, int64_t val) { -#define jso ((struct json_object_base *)jso) struct json_object_int *jsoint; if (!jso || jso->o_type != json_type_int) return 0; @@ -1126,7 +951,6 @@ int json_object_int_inc(struct json_object *jso, int64_t val) return 1; default: json_abort("invalid cint_type"); } -#undef jso } /* json_object_double */ @@ -1178,7 +1002,6 @@ int json_c_set_serialization_double_format(const char *double_format, int global static int json_object_double_to_json_string_format(struct json_object *jso, struct printbuf *pb, int level, int flags, const char *format) { -#define jso ((struct json_object_base *)jso) struct json_object_double *jsodbl = JC_DOUBLE(jso); char buf[128], *p, *q; int size; @@ -1268,24 +1091,19 @@ static int json_object_double_to_json_string_format(struct json_object *jso, str size = sizeof(buf) - 1; printbuf_memappend(pb, buf, size); return size; -#undef jso } static int json_object_double_to_json_string_default(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) - return json_object_double_to_json_string_format(PUBLIC(jso), pb, level, flags, NULL); -#undef jso + return json_object_double_to_json_string_format(jso, pb, level, flags, NULL); } int json_object_double_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) - return json_object_double_to_json_string_format(PUBLIC(jso), pb, level, flags, + return json_object_double_to_json_string_format(jso, pb, level, flags, (const char *)jso->_userdata); -#undef jso } struct json_object *json_object_new_double(double d) @@ -1295,7 +1113,7 @@ struct json_object *json_object_new_double(double d) return NULL; jso->base._to_json_string = &json_object_double_to_json_string_default; jso->c_double = d; - return PUBLIC(&jso->base); + return &jso->base; } struct json_object *json_object_new_double_s(double d, const char *ds) @@ -1331,21 +1149,9 @@ static int _json_object_userdata_to_json_string(struct json_object *jso, struct int json_object_userdata_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { - // XAX old code compat, remove this - if (!jso->newold) - { - int userdata_len = strlen((const char *)jso->_userdata); - printbuf_memappend(pb, (const char *)jso->_userdata, userdata_len); - return userdata_len; - } - else - { -#define jso ((const struct json_object_base *)jso) int userdata_len = strlen((const char *)jso->_userdata); printbuf_memappend(pb, (const char *)jso->_userdata, userdata_len); return userdata_len; -#undef jso - } } void json_object_free_userdata(struct json_object *jso, void *userdata) @@ -1355,7 +1161,6 @@ void json_object_free_userdata(struct json_object *jso, void *userdata) double json_object_get_double(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) double cdouble; char *errPtr = NULL; @@ -1410,19 +1215,16 @@ double json_object_get_double(const struct json_object *jso) return cdouble; default: errno = EINVAL; return 0.0; } -#undef jso } int json_object_set_double(struct json_object *jso, double new_value) { -#define jso ((struct json_object_base *)jso) if (!jso || jso->o_type != json_type_double) return 0; JC_DOUBLE(jso)->c_double = new_value; if (jso->_to_json_string == &_json_object_userdata_to_json_string) - json_object_set_serializer(PUBLIC(jso), NULL, NULL, NULL); + json_object_set_serializer(jso, NULL, NULL, NULL); return 1; -#undef jso } /* json_object_string */ @@ -1430,22 +1232,18 @@ int json_object_set_double(struct json_object *jso, double new_value) static int json_object_string_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) ssize_t len = JC_STRING(jso)->len; printbuf_strappend(pb, "\""); json_escape_str(pb, get_string_component(jso), len < 0 ? -(ssize_t)len : len, flags); printbuf_strappend(pb, "\""); return 0; -#undef jso } static void json_object_string_delete(struct json_object *jso) { -#define jso ((struct json_object_base *)jso) if (JC_STRING(jso)->len < 0) free(JC_STRING(jso)->c_string.pdata); - Xjson_object_generic_delete(jso); -#undef jso + json_object_generic_delete(jso); } static struct json_object *_json_object_new_string(const char *s, const size_t len) @@ -1457,7 +1255,7 @@ static struct json_object *_json_object_new_string(const char *s, const size_t l * Structures Actual memory layout * ------------------- -------------------- * [json_object_string [json_object_string - * [json_object_base] [json_object_base] + * [json_object] [json_object] * ...other fields... ...other fields... * c_string] len * bytes @@ -1474,7 +1272,7 @@ static struct json_object *_json_object_new_string(const char *s, const size_t l // so we can stuff a pointer into pdata :( objsize += sizeof(void *) - len; - jso = (struct json_object_string *)Xjson_object_new(json_type_string, objsize, + jso = (struct json_object_string *)json_object_new(json_type_string, objsize, &json_object_string_to_json_string, &json_object_string_delete); if (!jso) @@ -1482,7 +1280,7 @@ static struct json_object *_json_object_new_string(const char *s, const size_t l jso->len = len; memcpy(jso->c_string.idata, s, len); jso->c_string.idata[len] = '\0'; - return PUBLIC(&jso->base); + return &jso->base; } struct json_object *json_object_new_string(const char *s) @@ -1497,19 +1295,16 @@ struct json_object *json_object_new_string_len(const char *s, const int len) const char *json_object_get_string(struct json_object *jso) { -#define jso ((struct json_object_base *)jso) if (!jso) return NULL; switch (jso->o_type) { case json_type_string: return get_string_component(jso); - default: return json_object_to_json_string(PUBLIC(jso)); + default: return json_object_to_json_string(jso); } -#undef jso } int json_object_get_string_len(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) ssize_t len; if (!jso) return 0; @@ -1520,12 +1315,10 @@ int json_object_get_string_len(const struct json_object *jso) return (len < 0) ? -(ssize_t)len : len; default: return 0; } -#undef jso } static int _json_object_set_string_len(json_object *jso, const char *s, size_t len) { -#define jso ((struct json_object_base *)jso) char *dstbuf; ssize_t curlen; ssize_t newlen; @@ -1567,7 +1360,6 @@ static int _json_object_set_string_len(json_object *jso, const char *s, size_t l dstbuf[len] = '\0'; JC_STRING(jso)->len = newlen; return 1; -#undef jso } int json_object_set_string(json_object *jso, const char *s) @@ -1585,14 +1377,13 @@ int json_object_set_string_len(json_object *jso, const char *s, int len) static int json_object_array_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int flags) { -#define jso ((struct json_object_base *)jso) int had_children = 0; size_t ii; printbuf_strappend(pb, "["); if (flags & JSON_C_TO_STRING_PRETTY) printbuf_strappend(pb, "\n"); - for (ii = 0; ii < json_object_array_length(PUBLIC(jso)); ii++) + for (ii = 0; ii < json_object_array_length(jso); ii++) { struct json_object *val; if (had_children) @@ -1605,7 +1396,7 @@ static int json_object_array_to_json_string(struct json_object *jso, struct prin if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) printbuf_strappend(pb, " "); indent(pb, level + 1, flags); - val = json_object_array_get_idx(PUBLIC(jso), ii); + val = json_object_array_get_idx(jso, ii); if (val == NULL) printbuf_strappend(pb, "null"); else if (val->_to_json_string(val, pb, level + 1, flags) < 0) @@ -1621,7 +1412,6 @@ static int json_object_array_to_json_string(struct json_object *jso, struct prin if (flags & JSON_C_TO_STRING_SPACED && !(flags & JSON_C_TO_STRING_PRETTY)) return printbuf_strappend(pb, " ]"); return printbuf_strappend(pb, "]"); -#undef jso } static void json_object_array_entry_free(void *data) @@ -1631,10 +1421,8 @@ static void json_object_array_entry_free(void *data) static void json_object_array_delete(struct json_object *jso) { -#define jso ((struct json_object_base *)jso) array_list_free(JC_ARRAY(jso)->c_array); - Xjson_object_generic_delete(jso); -#undef jso + json_object_generic_delete(jso); } struct json_object *json_object_new_array(void) @@ -1648,12 +1436,11 @@ struct json_object *json_object_new_array(void) free(jso); return NULL; } - return PUBLIC(&jso->base); + return &jso->base; } struct array_list *json_object_get_array(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) if (!jso) return NULL; switch (jso->o_type) @@ -1661,72 +1448,57 @@ struct array_list *json_object_get_array(const struct json_object *jso) case json_type_array: return JC_ARRAY_C(jso)->c_array; default: return NULL; } -#undef jso } void json_object_array_sort(struct json_object *jso, int (*sort_fn)(const void *, const void *)) { -#define jso ((struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); array_list_sort(JC_ARRAY(jso)->c_array, sort_fn); -#undef jso } struct json_object *json_object_array_bsearch(const struct json_object *key, const struct json_object *jso, int (*sort_fn)(const void *, const void *)) { -#define jso ((const struct json_object_base *)jso) struct json_object **result; - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); result = (struct json_object **)array_list_bsearch((const void **)(void *)&key, JC_ARRAY_C(jso)->c_array, sort_fn); if (!result) return NULL; return *result; -#undef jso } size_t json_object_array_length(const struct json_object *jso) { -#define jso ((const struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); return array_list_length(JC_ARRAY_C(jso)->c_array); -#undef jso } int json_object_array_add(struct json_object *jso, struct json_object *val) { -#define jso ((struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); return array_list_add(JC_ARRAY(jso)->c_array, val); -#undef jso } int json_object_array_put_idx(struct json_object *jso, size_t idx, struct json_object *val) { -#define jso ((struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); return array_list_put_idx(JC_ARRAY(jso)->c_array, idx, val); -#undef jso } int json_object_array_del_idx(struct json_object *jso, size_t idx, size_t count) { -#define jso ((struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); return array_list_del_idx(JC_ARRAY(jso)->c_array, idx, count); -#undef jso } struct json_object *json_object_array_get_idx(const struct json_object *jso, size_t idx) { -#define jso ((const struct json_object_base *)jso) - assert(json_object_get_type(PUBLIC_C(jso)) == json_type_array); + assert(json_object_get_type(jso) == json_type_array); return (struct json_object *)array_list_get_idx(JC_ARRAY_C(jso)->c_array, idx); -#undef jso } static int json_array_equal(struct json_object *jso1, struct json_object *jso2) @@ -1751,13 +1523,13 @@ struct json_object *json_object_new_null(void) return NULL; } -static int json_object_all_values_equal(struct json_object_base *jso1, struct json_object_base *jso2) +static int json_object_all_values_equal(struct json_object *jso1, struct json_object *jso2) { struct json_object_iter iter; struct json_object *sub; - assert(json_object_get_type(PUBLIC(jso1)) == json_type_object); - assert(json_object_get_type(PUBLIC(jso2)) == json_type_object); + assert(json_object_get_type(jso1) == json_type_object); + assert(json_object_get_type(jso2) == json_type_object); /* Iterate over jso1 keys and see if they exist and are equal in jso2 */ json_object_object_foreachC(jso1, iter) { @@ -1777,58 +1549,6 @@ static int json_object_all_values_equal(struct json_object_base *jso1, struct js return 1; } -static int Xjson_object_equal(struct json_object *jso1, struct json_object *jso2) -{ - if (jso1 == jso2) - return 1; - - if (!jso1 || !jso2) - return 0; - - if (jso1->o_type != jso2->o_type) - return 0; - - switch (jso1->o_type) - { - case json_type_boolean: assert(0); //return (jso1->o.c_boolean == jso2->o.c_boolean); - - case json_type_double: assert(0); // return (jso1->o.c_double == jso2->o.c_double); - - case json_type_int: assert(0); - /* - if (jso1->o.c_int.cint_type == json_object_int_type_int64) - { - if (jso2->o.c_int.cint_type == json_object_int_type_int64) - return (jso1->o.c_int.cint.c_int64 == jso2->o.c_int.cint.c_int64); - if (jso1->o.c_int.cint.c_int64 < 0) - return 0; - return ((uint64_t)jso1->o.c_int.cint.c_int64 == - jso2->o.c_int.cint.c_uint64); - } - // else jso1 is a uint64 - if (jso2->o.c_int.cint_type == json_object_int_type_uint64) - return (jso1->o.c_int.cint.c_uint64 == jso2->o.c_int.cint.c_uint64); - if (jso2->o.c_int.cint.c_int64 < 0) - return 0; - return (jso1->o.c_int.cint.c_uint64 == (uint64_t)jso2->o.c_int.cint.c_int64); - */ - - case json_type_string: assert(0); - /* - return (jso1->o.c_string.len == jso2->o.c_string.len && - memcmp(get_string_component(jso1), get_string_component(jso2), - jso1->o.c_string.len) == 0); - */ - - case json_type_object: assert(0); //return json_object_all_values_equal(jso1, jso2); - - case json_type_array: assert(0); //return json_array_equal(jso1, jso2); - - case json_type_null: return 1; - }; - - return 0; -} int json_object_equal(struct json_object *jso1, struct json_object *jso2) { if (jso1 == jso2) @@ -1837,12 +1557,6 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) if (!jso1 || !jso2) return 0; - // XAX cut this after conversion - if (!jso1->newold && !jso2->newold) - return Xjson_object_equal(jso1, jso2); // call old code - -#define jso1 ((struct json_object_base *)jso1) -#define jso2 ((struct json_object_base *)jso2) if (jso1->o_type != jso2->o_type) return 0; @@ -1875,50 +1589,22 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) case json_type_string: { - return (json_object_get_string_len(PUBLIC(jso1)) == json_object_get_string_len(PUBLIC(jso2)) && - memcmp(get_string_component(jso1), get_string_component(jso2), json_object_get_string_len(PUBLIC(jso1))) == 0); + return (json_object_get_string_len(jso1) == json_object_get_string_len(jso2) && + memcmp(get_string_component(jso1), get_string_component(jso2), json_object_get_string_len(jso1)) == 0); } case json_type_object: return json_object_all_values_equal(jso1, jso2); - case json_type_array: return json_array_equal(PUBLIC(jso1), PUBLIC(jso2)); + case json_type_array: return json_array_equal(jso1, jso2); case json_type_null: return 1; }; return 0; -#undef jso1 -#undef jso2 } -// XAX remove this function after code conversion -static int Xjson_object_copy_serializer_data(struct json_object *src, struct json_object *dst) -{ - if (!src->_userdata && !src->_user_delete) - return 0; - - if (dst->_to_json_string == json_object_userdata_to_json_string || - dst->_to_json_string == _json_object_userdata_to_json_string) - { - dst->_userdata = strdup(src->_userdata); - } - // else if ... other supported serializers ... - else - { - _json_c_set_last_err( - "json_object_deep_copy: unable to copy unknown serializer data: %p\n", - dst->_to_json_string); - return -1; - } - dst->_user_delete = src->_user_delete; - return 0; -} static int json_object_copy_serializer_data(struct json_object *src, struct json_object *dst) { - if (!src->newold) - return Xjson_object_copy_serializer_data(src, dst); -#define src ((struct json_object_base *)src) -#define dst ((struct json_object_base *)dst) if (!src->_userdata && !src->_user_delete) return 0; @@ -1937,8 +1623,6 @@ static int json_object_copy_serializer_data(struct json_object *src, struct json } dst->_user_delete = src->_user_delete; return 0; -#undef src -#undef dst } /** @@ -1954,7 +1638,6 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha { switch (src->o_type) { -#define src ((struct json_object_base *)src) case json_type_boolean: *dst = json_object_new_boolean(JC_BOOL(src)->c_boolean); break; case json_type_double: *dst = json_object_new_double(JC_DOUBLE(src)->c_double); break; @@ -1989,7 +1672,6 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha (*dst)->_to_json_string = src->_to_json_string; // _userdata and _user_delete are copied later return 1; -#undef src } /* @@ -1998,16 +1680,16 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha * * Note: caller is responsible for freeing *dst if this fails and returns -1. */ -static int json_object_deep_copy_recursive(struct json_object_base *src, struct json_object_base *parent, +static int json_object_deep_copy_recursive(struct json_object *src, struct json_object *parent, const char *key_in_parent, size_t index_in_parent, - struct json_object_base **dst, + struct json_object **dst, json_c_shallow_copy_fn *shallow_copy) { struct json_object_iter iter; size_t src_array_len, ii; int shallow_copy_rc = 0; - shallow_copy_rc = shallow_copy(PUBLIC(src), PUBLIC(parent), key_in_parent, index_in_parent, (struct json_object **)dst); // XAX remove cast too + shallow_copy_rc = shallow_copy(src, parent, key_in_parent, index_in_parent, dst); /* -1=error, 1=object created ok, 2=userdata set */ if (shallow_copy_rc < 1) { @@ -2021,44 +1703,44 @@ static int json_object_deep_copy_recursive(struct json_object_base *src, struct case json_type_object: json_object_object_foreachC(src, iter) { - struct json_object_base *jso = NULL; + struct json_object *jso = NULL; /* This handles the `json_type_null` case */ if (!iter.val) jso = NULL; - else if (json_object_deep_copy_recursive((struct json_object_base *)/*XAX removecast*/iter.val, src, iter.key, -1, &jso, + else if (json_object_deep_copy_recursive(iter.val, src, iter.key, -1, &jso, shallow_copy) < 0) { - json_object_put(PUBLIC(jso)); + json_object_put(jso); return -1; } - if (json_object_object_add(PUBLIC(*dst), iter.key, PUBLIC(jso)) < 0) + if (json_object_object_add(*dst, iter.key, jso) < 0) { - json_object_put(PUBLIC(jso)); + json_object_put(jso); return -1; } } break; case json_type_array: - src_array_len = json_object_array_length(PUBLIC(src)); + src_array_len = json_object_array_length(src); for (ii = 0; ii < src_array_len; ii++) { - struct json_object_base *jso = NULL; - struct json_object_base *jso1 = (struct json_object_base *)/*XAXremovecast*/json_object_array_get_idx(PUBLIC(src), ii); + struct json_object *jso = NULL; + struct json_object *jso1 = json_object_array_get_idx(src, ii); /* This handles the `json_type_null` case */ if (!jso1) jso = NULL; else if (json_object_deep_copy_recursive(jso1, src, NULL, ii, &jso, shallow_copy) < 0) { - json_object_put(PUBLIC(jso)); + json_object_put(jso); return -1; } - if (json_object_array_add(PUBLIC(*dst), PUBLIC(jso)) < 0) + if (json_object_array_add(*dst, jso) < 0) { - json_object_put(PUBLIC(jso)); + json_object_put(jso); return -1; } } @@ -2070,7 +1752,7 @@ static int json_object_deep_copy_recursive(struct json_object_base *src, struct } if (shallow_copy_rc != 2) - return json_object_copy_serializer_data(PUBLIC(src), PUBLIC(*dst)); + return json_object_copy_serializer_data(src, *dst); return 0; } @@ -2078,9 +1760,6 @@ static int json_object_deep_copy_recursive(struct json_object_base *src, struct int json_object_deep_copy(struct json_object *src, struct json_object **dst, json_c_shallow_copy_fn *shallow_copy) { -#define src ((struct json_object_base *)src) -#define parent ((struct json_object_base *)parent) -#define dst ((struct json_object_base **)dst) int rc; /* Check if arguments are sane ; *dst must not point to a non-NULL object */ @@ -2096,14 +1775,11 @@ int json_object_deep_copy(struct json_object *src, struct json_object **dst, rc = json_object_deep_copy_recursive(src, NULL, NULL, -1, dst, shallow_copy); if (rc < 0) { - json_object_put(PUBLIC(*dst)); + json_object_put(*dst); *dst = NULL; } return rc; -#undef src -#undef parent -#undef dst } static void json_abort(const char *message) diff --git a/json_object.h b/json_object.h index 1805bda..7c0d1f2 100644 --- a/json_object.h +++ b/json_object.h @@ -490,9 +490,8 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key * @param obj the json_object instance * @param iter the object iterator, use type json_object_iter */ -// XAX temporary workaround during code conversion: #define json_object_object_foreachC(obj, iter) \ - for (iter.entry = json_object_get_object(PUBLIC(obj))->head; \ + for (iter.entry = json_object_get_object(obj)->head; \ (iter.entry ? (iter.key = (char *)lh_entry_k(iter.entry), \ iter.val = (struct json_object *)lh_entry_v(iter.entry), iter.entry) \ : 0); \ diff --git a/json_object_private.h b/json_object_private.h index bfe2b1c..c7b4d1f 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -20,14 +20,11 @@ extern "C" { #endif -/**< how many bytes are directly stored in json_object for strings? */ -#define LEN_DIRECT_STRING_DATA 32 - struct json_object; #include "json_inttypes.h" #include "json_types.h" -typedef void(json_object_private_delete_fn)(struct json_object *o); +typedef void (json_object_private_delete_fn)(struct json_object *o); /* json object int type, support extension*/ typedef enum json_object_int_type @@ -36,9 +33,8 @@ typedef enum json_object_int_type json_object_int_type_uint64 } json_object_int_type; -struct json_object_base // XAX rename to json_object after conversion +struct json_object { - int newold; // XAX temporary, remove after code conversion enum json_type o_type; uint32_t _ref_count; json_object_private_delete_fn *_delete; @@ -51,28 +47,28 @@ struct json_object_base // XAX rename to json_object after conversion struct json_object_object { - struct json_object_base base; + struct json_object base; struct lh_table *c_object; }; struct json_object_array { - struct json_object_base base; + struct json_object base; struct array_list *c_array; }; struct json_object_boolean { - struct json_object_base base; + struct json_object base; json_bool c_boolean; }; struct json_object_double { - struct json_object_base base; + struct json_object base; double c_double; }; struct json_object_int { - struct json_object_base base; + struct json_object base; enum json_object_int_type cint_type; union { @@ -82,7 +78,7 @@ struct json_object_int }; struct json_object_string { - struct json_object_base base; + struct json_object base; ssize_t len; // Signed b/c negative lengths indicate data is a pointer // Consider adding an "alloc" field here, if json_object_set_string calls // to expand the length of a string are common operations to perform. @@ -93,21 +89,6 @@ struct json_object_string } c_string; }; -struct json_object -{ - int newold; - enum json_type o_type; - uint32_t _ref_count; - json_object_private_delete_fn *_delete; - json_object_to_json_string_fn *_to_json_string; - struct printbuf *_pb; - int dummyval; // XAX temp spacer to catch casting errors - int du1mmyval; // XAX spacer - int d2ummyval; // XAX spacer - json_object_delete_fn *_user_delete; - void *_userdata; -}; - void _json_c_set_last_err(const char *err_fmt, ...); extern const char *json_number_chars; diff --git a/tests/test_double_serializer.c b/tests/test_double_serializer.c index 98f6dd9..38de6b5 100644 --- a/tests/test_double_serializer.c +++ b/tests/test_double_serializer.c @@ -20,7 +20,7 @@ int main() printf("obj.to_string(standard)=%s\n", json_object_to_json_string(obj)); printf("Test default serializer with custom userdata:\n"); - ((struct json_object_base *)obj)->_userdata = udata; + ((struct json_object *)obj)->_userdata = udata; printf("obj.to_string(userdata)=%s\n", json_object_to_json_string(obj)); printf("Test explicit serializer with custom userdata:\n"); diff --git a/tests/test_set_value.c b/tests/test_set_value.c index eb0fe8b..157e64f 100644 --- a/tests/test_set_value.c +++ b/tests/test_set_value.c @@ -56,12 +56,12 @@ int main(int argc, char **argv) #define MID "A MID STRING" // 12345678901234567890123456789012.... #define HUGE "A string longer than 32 chars as to check non local buf codepath" - tmp = json_object_new_string(SHORT); - assert(strcmp(json_object_get_string(tmp), SHORT) == 0); - assert(strcmp(json_object_to_json_string(tmp), "\"" SHORT "\"") == 0); - json_object_set_string(tmp, MID); + tmp = json_object_new_string(MID); assert(strcmp(json_object_get_string(tmp), MID) == 0); assert(strcmp(json_object_to_json_string(tmp), "\"" MID "\"") == 0); + json_object_set_string(tmp, SHORT); + assert(strcmp(json_object_get_string(tmp), SHORT) == 0); + assert(strcmp(json_object_to_json_string(tmp), "\"" SHORT "\"") == 0); json_object_set_string(tmp, HUGE); assert(strcmp(json_object_get_string(tmp), HUGE) == 0); assert(strcmp(json_object_to_json_string(tmp), "\"" HUGE "\"") == 0); From ecdfeb18cf8df1bf519785f3353d1e4ab87c3a9c Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 18:29:56 +0000 Subject: [PATCH 26/94] Move the ssize_t typedef from json_inttypes.h to json_object_private.h so as not to affect publically exposed symbols. --- json_inttypes.h | 5 ----- json_object_private.h | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/json_inttypes.h b/json_inttypes.h index e51da74..e047d4f 100644 --- a/json_inttypes.h +++ b/json_inttypes.h @@ -21,9 +21,4 @@ #endif -#ifdef _MSC_VER -#include -typedef SSIZE_T ssize_t; -#endif - #endif diff --git a/json_object_private.h b/json_object_private.h index c7b4d1f..8132a33 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -24,6 +24,11 @@ struct json_object; #include "json_inttypes.h" #include "json_types.h" +#ifdef _MSC_VER +#include +typedef SSIZE_T ssize_t; +#endif + typedef void (json_object_private_delete_fn)(struct json_object *o); /* json object int type, support extension*/ From 02fe2e0ccd77dfed8ae02e4abd8d41c5379364f7 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 18:45:17 +0000 Subject: [PATCH 27/94] Summarize the changes from the json_object-split branch in the ChangeLog. --- ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index 8a58d19..afb5155 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,13 @@ Other changes * Issue #471: always create directories with mode 0755, regardless of umask. * Added a JSON_TOKENER_ALLOW_TRAILING_CHARS flag to allow multiple objects to be parsed even when JSON_TOKENER_STRICT is set. +* Split the internal json_object structure into several sub-types, one for + each json_type (json_object_object, json_object_string, etc...). + This improves memory usage and speed, with the benchmark under + bench/ report 5.8% faster test time and 6%(max RSS)-12%(peak heap) + less memory usage. + Memory used just for json_object structures decreased 27%, so use cases + with fewer arrays and/or strings would benefit more. *** From 85c244f04807689621fca58075ab4946fad5e996 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 7 Jun 2020 18:50:10 +0000 Subject: [PATCH 28/94] Eliminate unnecessary cast that was added to test_double_serializer. --- tests/test_double_serializer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_double_serializer.c b/tests/test_double_serializer.c index 38de6b5..8b2487a 100644 --- a/tests/test_double_serializer.c +++ b/tests/test_double_serializer.c @@ -20,7 +20,7 @@ int main() printf("obj.to_string(standard)=%s\n", json_object_to_json_string(obj)); printf("Test default serializer with custom userdata:\n"); - ((struct json_object *)obj)->_userdata = udata; + obj->_userdata = udata; printf("obj.to_string(userdata)=%s\n", json_object_to_json_string(obj)); printf("Test explicit serializer with custom userdata:\n"); From c1b872d8174c9946f8d9383fe600e8ff6650647e Mon Sep 17 00:00:00 2001 From: dota17 Date: Tue, 2 Jun 2020 19:17:42 +0800 Subject: [PATCH 29/94] fix issue 616: support the surrogate pair in split file. --- json_tokener.c | 25 ++++++++--- json_tokener.h | 2 +- tests/test_parse.c | 95 ++++++++++++++++++++++++++++----------- tests/test_parse.expected | 26 ++++++++++- 4 files changed, 113 insertions(+), 35 deletions(-) diff --git a/json_tokener.c b/json_tokener.c index 0373d6f..69d7af2 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -630,8 +630,6 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * case json_tokener_state_escape_unicode: { - unsigned int got_hi_surrogate = 0; - /* Handle a 4-byte sequence, or two sequences if a surrogate pair */ while (1) { @@ -643,14 +641,24 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * { unsigned char unescaped_utf[4]; - if (got_hi_surrogate) + if (tok->got_hi_surrogate) { if (IS_LOW_SURROGATE(tok->ucs_char)) { + /* remove the utf8_replacement_char */ + /* which may generate during */ + /* parsing the high surrogate pair. */ + if (!strcmp( + tok->pb->buf, + (char *) + utf8_replacement_char)) + { + printbuf_reset(tok->pb); + } /* Recalculate the ucs_char, then fall thru to process normally */ tok->ucs_char = DECODE_SURROGATE_PAIR( - got_hi_surrogate, + tok->got_hi_surrogate, tok->ucs_char); } else @@ -662,7 +670,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * (char *)utf8_replacement_char, 3); } - got_hi_surrogate = 0; + tok->got_hi_surrogate = 0; } if (tok->ucs_char < 0x80) @@ -686,7 +694,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * * the beginning of another sequence, which * should be the low surrogate. */ - got_hi_surrogate = tok->ucs_char; + tok->got_hi_surrogate = tok->ucs_char; /* Not at end, and the next two chars should be "\u" */ if ((len == -1 || len > (tok->char_offset + 2)) && @@ -717,6 +725,8 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * (char *) utf8_replacement_char, 3); + tok->ucs_char = 0; + tok->st_pos = 0; goto out; } tok->ucs_char = 0; @@ -786,7 +796,8 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) { /* Clean up any pending chars */ - if (got_hi_surrogate) + if (tok->got_hi_surrogate && + strcmp(tok->pb->buf, (char *)utf8_replacement_char)) printbuf_memappend_fast( tok->pb, (char *)utf8_replacement_char, 3); goto out; diff --git a/json_tokener.h b/json_tokener.h index ea49ad8..8afa6ec 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -111,7 +111,7 @@ struct json_tokener * @deprecated See json_tokener_get_error() instead. */ enum json_tokener_error err; - unsigned int ucs_char; + unsigned int ucs_char, got_hi_surrogate; char quote_char; struct json_tokener_srec *stack; int flags; diff --git a/tests/test_parse.c b/tests/test_parse.c index 6014ac1..42b2fdf 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -224,6 +224,35 @@ struct incremental_step {"\": {\"bar", -1, -1, json_tokener_continue, 0}, {"\":13}}", -1, -1, json_tokener_success, 1}, + /* Check the UTF-16 surrogate pair */ + /* parse one char at every time */ + {"\"\\", -1, -1, json_tokener_continue, 0}, + {"u", -1, -1, json_tokener_continue, 0}, + {"d", -1, -1, json_tokener_continue, 0}, + {"8", -1, -1, json_tokener_continue, 0}, + {"3", -1, -1, json_tokener_continue, 0}, + {"4", -1, -1, json_tokener_continue, 0}, + {"\\", -1, -1, json_tokener_continue, 0}, + {"u", -1, -1, json_tokener_continue, 0}, + {"d", -1, -1, json_tokener_continue, 0}, + {"d", -1, -1, json_tokener_continue, 0}, + {"1", -1, -1, json_tokener_continue, 0}, + {"e\"", -1, -1, json_tokener_success, 1}, + /* parse two char at every time */ + {"\"\\u", -1, -1, json_tokener_continue, 0}, + {"d8", -1, -1, json_tokener_continue, 0}, + {"34", -1, -1, json_tokener_continue, 0}, + {"\\u", -1, -1, json_tokener_continue, 0}, + {"dd", -1, -1, json_tokener_continue, 0}, + {"1e\"", -1, -1, json_tokener_success, 1}, + /* check the low surrogate pair */ + {"\"\\ud834", -1, -1, json_tokener_continue, 0}, + {"\\udd1e\"", -1, -1, json_tokener_success, 1}, + {"\"\\ud834\\", -1, -1, json_tokener_continue, 0}, + {"udd1e\"", -1, -1, json_tokener_success, 1}, + {"\"\\ud834\\u", -1, -1, json_tokener_continue, 0}, + {"dd1e\"", -1, -1, json_tokener_success, 1}, + /* Check that json_tokener_reset actually resets */ {"{ \"foo", -1, -1, json_tokener_continue, 1}, {": \"bar\"}", -1, 0, json_tokener_error_parse_unexpected, 1}, @@ -239,11 +268,13 @@ struct incremental_step {"\"Y\"", -1, -1, json_tokener_success, 1}, /* Trailing characters should cause a failure in strict mode */ - {"{\"foo\":9}{\"bar\":8}", -1, 9, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT }, + {"{\"foo\":9}{\"bar\":8}", -1, 9, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT}, /* ... unless explicitly allowed. */ - {"{\"foo\":9}{\"bar\":8}", -1, 9, json_tokener_success, 0, JSON_TOKENER_STRICT|JSON_TOKENER_ALLOW_TRAILING_CHARS }, - {"{\"b\":8}ignored garbage", -1, 7, json_tokener_success, 1, JSON_TOKENER_STRICT|JSON_TOKENER_ALLOW_TRAILING_CHARS }, + {"{\"foo\":9}{\"bar\":8}", -1, 9, json_tokener_success, 0, + JSON_TOKENER_STRICT | JSON_TOKENER_ALLOW_TRAILING_CHARS}, + {"{\"b\":8}ignored garbage", -1, 7, json_tokener_success, 1, + JSON_TOKENER_STRICT | JSON_TOKENER_ALLOW_TRAILING_CHARS}, /* To stop parsing a number we need to reach a non-digit, e.g. a \0 */ {"1", 1, 1, json_tokener_continue, 0}, @@ -251,7 +282,7 @@ struct incremental_step {"2", 2, 1, json_tokener_success, 0}, {"12{", 3, 2, json_tokener_success, 1}, /* Parse number in strict model */ - {"[02]", -1, 3, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT }, + {"[02]", -1, 3, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, /* Similar tests for other kinds of objects: */ /* These could all return success immediately, since regardless of @@ -267,8 +298,8 @@ struct incremental_step {"Infinity", 9, 8, json_tokener_success, 1}, {"infinity", 9, 8, json_tokener_success, 1}, {"-infinity", 10, 9, json_tokener_success, 1}, - {"infinity", 9, 0, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT }, - {"-infinity", 10, 1, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT }, + {"infinity", 9, 0, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT}, + {"-infinity", 10, 1, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT}, {"inf", 3, 3, json_tokener_continue, 0}, {"inity", 6, 5, json_tokener_success, 1}, @@ -350,7 +381,7 @@ struct incremental_step {"\"\\a\"", -1, 2, json_tokener_error_parse_string, 1}, /* Check '\'' in strict model */ - {"\'foo\'", -1, 0, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT }, + {"\'foo\'", -1, 0, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT}, /* Parse array/object */ {"[1,2,3]", -1, -1, json_tokener_success, 0}, @@ -372,42 +403,54 @@ struct incremental_step {"[1,2,3,]", -1, -1, json_tokener_success, 0}, {"[1,2,,3,]", -1, 5, json_tokener_error_parse_unexpected, 0}, - {"[1,2,3,]", -1, 7, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT }, - {"{\"a\":1,}", -1, 7, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT }, + {"[1,2,3,]", -1, 7, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT}, + {"{\"a\":1,}", -1, 7, json_tokener_error_parse_unexpected, 1, JSON_TOKENER_STRICT}, // utf-8 test // acsll encoding - {"\x22\x31\x32\x33\x61\x73\x63\x24\x25\x26\x22", -1, -1, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8 }, + {"\x22\x31\x32\x33\x61\x73\x63\x24\x25\x26\x22", -1, -1, json_tokener_success, 1, + JSON_TOKENER_VALIDATE_UTF8}, {"\x22\x31\x32\x33\x61\x73\x63\x24\x25\x26\x22", -1, -1, json_tokener_success, 1}, // utf-8 encoding - {"\x22\xe4\xb8\x96\xe7\x95\x8c\x22", -1, -1, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8 }, - {"\x22\xe4\xb8", -1, 3, json_tokener_error_parse_utf8_string, 0, JSON_TOKENER_VALIDATE_UTF8 }, - {"\x96\xe7\x95\x8c\x22", -1, 0, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8 }, + {"\x22\xe4\xb8\x96\xe7\x95\x8c\x22", -1, -1, json_tokener_success, 1, + JSON_TOKENER_VALIDATE_UTF8}, + {"\x22\xe4\xb8", -1, 3, json_tokener_error_parse_utf8_string, 0, JSON_TOKENER_VALIDATE_UTF8}, + {"\x96\xe7\x95\x8c\x22", -1, 0, json_tokener_error_parse_utf8_string, 1, + JSON_TOKENER_VALIDATE_UTF8}, {"\x22\xe4\xb8\x96\xe7\x95\x8c\x22", -1, -1, json_tokener_success, 1}, - {"\x22\xcf\x80\xcf\x86\x22", -1, -1, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8 }, - {"\x22\xf0\xa5\x91\x95\x22", -1, -1, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8 }, + {"\x22\xcf\x80\xcf\x86\x22", -1, -1, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8}, + {"\x22\xf0\xa5\x91\x95\x22", -1, -1, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8}, // wrong utf-8 encoding - {"\x22\xe6\x9d\x4e\x22", -1, 3, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8 }, + {"\x22\xe6\x9d\x4e\x22", -1, 3, json_tokener_error_parse_utf8_string, 1, + JSON_TOKENER_VALIDATE_UTF8}, {"\x22\xe6\x9d\x4e\x22", -1, 5, json_tokener_success, 1}, // GBK encoding - {"\x22\xc0\xee\xc5\xf4\x22", -1, 2, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8 }, + {"\x22\xc0\xee\xc5\xf4\x22", -1, 2, json_tokener_error_parse_utf8_string, 1, + JSON_TOKENER_VALIDATE_UTF8}, {"\x22\xc0\xee\xc5\xf4\x22", -1, 6, json_tokener_success, 1}, // char after space - {"\x20\x20\x22\xe4\xb8\x96\x22", -1, -1, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8 }, - {"\x20\x20\x81\x22\xe4\xb8\x96\x22", -1, 2, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8 }, - {"\x5b\x20\x81\x31\x5d", -1, 2, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8 }, + {"\x20\x20\x22\xe4\xb8\x96\x22", -1, -1, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8}, + {"\x20\x20\x81\x22\xe4\xb8\x96\x22", -1, 2, json_tokener_error_parse_utf8_string, 1, + JSON_TOKENER_VALIDATE_UTF8}, + {"\x5b\x20\x81\x31\x5d", -1, 2, json_tokener_error_parse_utf8_string, 1, + JSON_TOKENER_VALIDATE_UTF8}, // char in state inf {"\x49\x6e\x66\x69\x6e\x69\x74\x79", 9, 8, json_tokener_success, 1}, - {"\x49\x6e\x66\x81\x6e\x69\x74\x79", -1, 3, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8 }, + {"\x49\x6e\x66\x81\x6e\x69\x74\x79", -1, 3, json_tokener_error_parse_utf8_string, 1, + JSON_TOKENER_VALIDATE_UTF8}, // char in escape unicode - {"\x22\x5c\x75\x64\x38\x35\x35\x5c\x75\x64\x63\x35\x35\x22", 15, 14, json_tokener_success, 1, JSON_TOKENER_VALIDATE_UTF8 }, + {"\x22\x5c\x75\x64\x38\x35\x35\x5c\x75\x64\x63\x35\x35\x22", 15, 14, json_tokener_success, 1, + JSON_TOKENER_VALIDATE_UTF8}, {"\x22\x5c\x75\x64\x38\x35\x35\xc0\x75\x64\x63\x35\x35\x22", -1, 8, - json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8 }, - {"\x22\x5c\x75\x64\x30\x30\x33\x31\xc0\x22", -1, 9, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8 }, + json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8}, + {"\x22\x5c\x75\x64\x30\x30\x33\x31\xc0\x22", -1, 9, json_tokener_error_parse_utf8_string, 1, + JSON_TOKENER_VALIDATE_UTF8}, // char in number - {"\x31\x31\x81\x31\x31", -1, 2, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8 }, + {"\x31\x31\x81\x31\x31", -1, 2, json_tokener_error_parse_utf8_string, 1, + JSON_TOKENER_VALIDATE_UTF8}, // char in object - {"\x7b\x22\x31\x81\x22\x3a\x31\x7d", -1, 3, json_tokener_error_parse_utf8_string, 1, JSON_TOKENER_VALIDATE_UTF8 }, + {"\x7b\x22\x31\x81\x22\x3a\x31\x7d", -1, 3, json_tokener_error_parse_utf8_string, 1, + JSON_TOKENER_VALIDATE_UTF8}, {NULL, -1, -1, json_tokener_success, 0}, }; diff --git a/tests/test_parse.expected b/tests/test_parse.expected index 77e8be1..df74fbd 100644 --- a/tests/test_parse.expected +++ b/tests/test_parse.expected @@ -100,6 +100,30 @@ json_tokener_parse_ex(tok, // hello"foo", 13) ... OK: got correct error: contin json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue json_tokener_parse_ex(tok, ": {"bar , 8) ... OK: got correct error: continue json_tokener_parse_ex(tok, ":13}} , 6) ... OK: got object of type [object]: { "foo": { "bar": 13 } } +json_tokener_parse_ex(tok, "\ , 2) ... OK: got correct error: continue +json_tokener_parse_ex(tok, u , 1) ... OK: got correct error: continue +json_tokener_parse_ex(tok, d , 1) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 8 , 1) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 3 , 1) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 4 , 1) ... OK: got correct error: continue +json_tokener_parse_ex(tok, \ , 1) ... OK: got correct error: continue +json_tokener_parse_ex(tok, u , 1) ... OK: got correct error: continue +json_tokener_parse_ex(tok, d , 1) ... OK: got correct error: continue +json_tokener_parse_ex(tok, d , 1) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 1 , 1) ... OK: got correct error: continue +json_tokener_parse_ex(tok, e" , 2) ... OK: got object of type [string]: "ð„ž" +json_tokener_parse_ex(tok, "\u , 3) ... OK: got correct error: continue +json_tokener_parse_ex(tok, d8 , 2) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 34 , 2) ... OK: got correct error: continue +json_tokener_parse_ex(tok, \u , 2) ... OK: got correct error: continue +json_tokener_parse_ex(tok, dd , 2) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 1e" , 3) ... OK: got object of type [string]: "ð„ž" +json_tokener_parse_ex(tok, "\ud834 , 7) ... OK: got correct error: continue +json_tokener_parse_ex(tok, \udd1e" , 7) ... OK: got object of type [string]: "ð„ž" +json_tokener_parse_ex(tok, "\ud834\ , 8) ... OK: got correct error: continue +json_tokener_parse_ex(tok, udd1e" , 6) ... OK: got object of type [string]: "ð„ž" +json_tokener_parse_ex(tok, "\ud834\u , 9) ... OK: got correct error: continue +json_tokener_parse_ex(tok, dd1e" , 5) ... OK: got object of type [string]: "ð„ž" json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue json_tokener_parse_ex(tok, : "bar"} , 8) ... OK: got correct error: unexpected character json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue @@ -216,5 +240,5 @@ json_tokener_parse_ex(tok, "\ud855 json_tokener_parse_ex(tok, "\ud0031À" , 10) ... OK: got correct error: invalid utf-8 string json_tokener_parse_ex(tok, 1111 , 5) ... OK: got correct error: invalid utf-8 string json_tokener_parse_ex(tok, {"1":1} , 8) ... OK: got correct error: invalid utf-8 string -End Incremental Tests OK=130 ERROR=0 +End Incremental Tests OK=154 ERROR=0 ================================== From 4c10712114a79d1abf0d98ac165648a6aa36d45a Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 13 Jun 2020 18:25:32 +0000 Subject: [PATCH 30/94] Drop the useless "char data[1]" from struct json_object. Fix a typo in a comment. --- json_object.c | 2 +- json_object_private.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/json_object.c b/json_object.c index bed97cd..8615ff5 100644 --- a/json_object.c +++ b/json_object.c @@ -199,7 +199,7 @@ static inline char *get_string_component_mutable(struct json_object *jso) { if (JC_STRING_C(jso)->len < 0) { - /* Due to json_object_str_string(), we might have a pointer */ + /* Due to json_object_set_string(), we might have a pointer */ return JC_STRING(jso)->c_string.pdata; } return JC_STRING(jso)->c_string.idata; diff --git a/json_object_private.h b/json_object_private.h index 8132a33..7cd90c2 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -47,7 +47,8 @@ struct json_object struct printbuf *_pb; json_object_delete_fn *_user_delete; void *_userdata; - char data[1]; // Actually the rest of a struct json_object_${o_type} + // Actually longer, always malloc'd as some more-specific type. + // The rest of a struct json_object_${o_type} follows }; struct json_object_object From 5ebfeaedc5413452aff7fa733abfabe97df100e8 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 13 Jun 2020 18:34:35 +0000 Subject: [PATCH 31/94] Drop the _delete field from struct json_object and call the type-specific delete functions directly from json_object_put. (Thanks @dota17 for the suggestion in PR #632!) --- json_object.c | 46 ++++++++++++++++++++++++++++--------------- json_object_private.h | 3 --- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/json_object.c b/json_object.c index 8615ff5..42d4efd 100644 --- a/json_object.c +++ b/json_object.c @@ -121,15 +121,17 @@ static inline const struct json_object_string *JC_STRING_C(const struct json_obj #define JC_CONCAT(a,b) a##b #define JC_CONCAT3(a,b,c) a##b##c -#define JSON_OBJECT_NEW(jtype, delete_fn) \ +#define JSON_OBJECT_NEW(jtype) \ (struct JC_CONCAT(json_object_,jtype) *)json_object_new(JC_CONCAT(json_type_,jtype), \ sizeof(struct JC_CONCAT(json_object_,jtype)), \ - &JC_CONCAT3(json_object_,jtype,_to_json_string), \ - delete_fn) + &JC_CONCAT3(json_object_,jtype,_to_json_string)) static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, - json_object_to_json_string_fn *to_json_string, - json_object_private_delete_fn *delete_fn); + json_object_to_json_string_fn *to_json_string); + +static void json_object_object_delete(struct json_object *jso_base); +static void json_object_string_delete(struct json_object *jso); +static void json_object_array_delete(struct json_object *jso); static json_object_to_json_string_fn json_object_object_to_json_string; static json_object_to_json_string_fn json_object_boolean_to_json_string; @@ -322,7 +324,21 @@ int json_object_put(struct json_object *jso) if (jso->_user_delete) jso->_user_delete(jso, jso->_userdata); - jso->_delete(jso); + switch(jso->o_type) + { + case json_type_object: + json_object_object_delete(jso); + break; + case json_type_array: + json_object_array_delete(jso); + break; + case json_type_string: + json_object_string_delete(jso); + break; + default: + json_object_generic_delete(jso); + break; + } return 1; } @@ -341,8 +357,7 @@ static void json_object_generic_delete(struct json_object *jso) static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, - json_object_to_json_string_fn *to_json_string, - json_object_private_delete_fn *delete_fn) + json_object_to_json_string_fn *to_json_string) { struct json_object *jso; @@ -352,7 +367,6 @@ static inline struct json_object *json_object_new(enum json_type o_type, jso->o_type = o_type; jso->_ref_count = 1; - jso->_delete = delete_fn; jso->_to_json_string = to_json_string; jso->_pb = NULL; jso->_user_delete = NULL; @@ -552,7 +566,7 @@ static void json_object_object_delete(struct json_object *jso_base) struct json_object *json_object_new_object(void) { - struct json_object_object *jso = JSON_OBJECT_NEW(object, &json_object_object_delete); + struct json_object_object *jso = JSON_OBJECT_NEW(object); if (!jso) return NULL; jso->c_object = @@ -676,7 +690,7 @@ static int json_object_boolean_to_json_string(struct json_object *jso, struct pr struct json_object *json_object_new_boolean(json_bool b) { - struct json_object_boolean *jso = JSON_OBJECT_NEW(boolean, &json_object_generic_delete); + struct json_object_boolean *jso = JSON_OBJECT_NEW(boolean); if (!jso) return NULL; jso->c_boolean = b; @@ -794,7 +808,7 @@ int json_object_set_int(struct json_object *jso, int new_value) struct json_object *json_object_new_int64(int64_t i) { - struct json_object_int *jso = JSON_OBJECT_NEW(int, &json_object_generic_delete); + struct json_object_int *jso = JSON_OBJECT_NEW(int); if (!jso) return NULL; jso->cint.c_int64 = i; @@ -804,7 +818,7 @@ struct json_object *json_object_new_int64(int64_t i) struct json_object *json_object_new_uint64(uint64_t i) { - struct json_object_int *jso = JSON_OBJECT_NEW(int, &json_object_generic_delete); + struct json_object_int *jso = JSON_OBJECT_NEW(int); if (!jso) return NULL; jso->cint.c_uint64 = i; @@ -1108,7 +1122,7 @@ int json_object_double_to_json_string(struct json_object *jso, struct printbuf * struct json_object *json_object_new_double(double d) { - struct json_object_double *jso = JSON_OBJECT_NEW(double, &json_object_generic_delete); + struct json_object_double *jso = JSON_OBJECT_NEW(double); if (!jso) return NULL; jso->base._to_json_string = &json_object_double_to_json_string_default; @@ -1273,7 +1287,7 @@ static struct json_object *_json_object_new_string(const char *s, const size_t l objsize += sizeof(void *) - len; jso = (struct json_object_string *)json_object_new(json_type_string, objsize, - &json_object_string_to_json_string, &json_object_string_delete); + &json_object_string_to_json_string); if (!jso) return NULL; @@ -1427,7 +1441,7 @@ static void json_object_array_delete(struct json_object *jso) struct json_object *json_object_new_array(void) { - struct json_object_array *jso = JSON_OBJECT_NEW(array, &json_object_array_delete); + struct json_object_array *jso = JSON_OBJECT_NEW(array); if (!jso) return NULL; jso->c_array = array_list_new(&json_object_array_entry_free); diff --git a/json_object_private.h b/json_object_private.h index 7cd90c2..4413955 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -29,8 +29,6 @@ struct json_object; typedef SSIZE_T ssize_t; #endif -typedef void (json_object_private_delete_fn)(struct json_object *o); - /* json object int type, support extension*/ typedef enum json_object_int_type { @@ -42,7 +40,6 @@ struct json_object { enum json_type o_type; uint32_t _ref_count; - json_object_private_delete_fn *_delete; json_object_to_json_string_fn *_to_json_string; struct printbuf *_pb; json_object_delete_fn *_user_delete; From 9128ec49b126ad996468ab4df290916241e2864d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 14 Jun 2020 03:11:44 +0000 Subject: [PATCH 32/94] Include unistd.h to fix the build on OSX --- json_object_iterator.c | 1 + json_object_private.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/json_object_iterator.c b/json_object_iterator.c index 796015e..1c2b3f2 100644 --- a/json_object_iterator.c +++ b/json_object_iterator.c @@ -9,6 +9,7 @@ * ******************************************************************************* */ +#include "config.h" #include diff --git a/json_object_private.h b/json_object_private.h index 4413955..d8dacd2 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -24,6 +24,10 @@ struct json_object; #include "json_inttypes.h" #include "json_types.h" +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ + #ifdef _MSC_VER #include typedef SSIZE_T ssize_t; From 60494684a103f218503deb985631eae6331c31ec Mon Sep 17 00:00:00 2001 From: Micah Snyder Date: Sun, 14 Jun 2020 12:01:48 -0400 Subject: [PATCH 33/94] Issue #508: `-fPIC` to link libjson-c.a with libs json-c has symbol collisions with other popular C JSON libraries. To prevent random crashes in downstream applications that may use a library which depends on json-c, the solution is to statically link libjson-c.a into those libraries. `-fPIC`/`-fPIE` is required when building a `.a` so it can be linked into a `.so`. --- CMakeLists.txt | 8 ++++++++ README.md | 1 + 2 files changed, 9 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b52255f..bfd9c3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,6 +110,14 @@ if (MSVC) list(APPEND CMAKE_REQUIRED_FLAGS /wd4996) endif() +if (NOT DISABLE_STATIC_FPIC) + # Use '-fPIC'/'-fPIE' option. + # This will allow other libraries to statically link in libjson-c.a + # which in turn prevents crashes in downstream apps that may use + # a different JSON library with identical symbol names. + set(CMAKE_POSITION_INDEPENDENT_CODE ON) +endif() + check_include_file("fcntl.h" HAVE_FCNTL_H) check_include_file("inttypes.h" HAVE_INTTYPES_H) check_include_file(stdarg.h HAVE_STDARG_H) diff --git a/README.md b/README.md index 5cabd9d..3757a40 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,7 @@ CMAKE_INSTALL_PREFIX | String | The install location. CMAKE_BUILD_TYPE | String | Defaults to "debug". BUILD_SHARED_LIBS | Bool | The default build generates a dynamic (dll/so) library. Set this to OFF to create a static library only. BUILD_STATIC_LIBS | Bool | The default build generates a static (lib/a) library. Set this to OFF to create a shared library only. +DISABLE_STATIC_FPIC | Bool | The default builds position independent code. Set this to OFF to create a shared library only. DISABLE_BSYMBOLIC | Bool | Disable use of -Bsymbolic-functions. DISABLE_THREAD_LOCAL_STORAGE | Bool | Disable use of Thread-Local Storage (HAVE___THREAD). DISABLE_WERROR | Bool | Disable use of -Werror. From 0710c835a1558f13e143da449fdd8c44956733e6 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 16 Jun 2020 13:17:58 +0000 Subject: [PATCH 34/94] Reformat the json_object-split branch with clang-format --- json_object.c | 69 +++++++++++++++++++------------------------ json_object_private.h | 2 +- 2 files changed, 32 insertions(+), 39 deletions(-) diff --git a/json_object.c b/json_object.c index 42d4efd..be84cb0 100644 --- a/json_object.c +++ b/json_object.c @@ -118,16 +118,16 @@ static inline const struct json_object_string *JC_STRING_C(const struct json_obj return (const void *)jso; } -#define JC_CONCAT(a,b) a##b -#define JC_CONCAT3(a,b,c) a##b##c +#define JC_CONCAT(a, b) a##b +#define JC_CONCAT3(a, b, c) a##b##c -#define JSON_OBJECT_NEW(jtype) \ - (struct JC_CONCAT(json_object_,jtype) *)json_object_new(JC_CONCAT(json_type_,jtype), \ - sizeof(struct JC_CONCAT(json_object_,jtype)), \ - &JC_CONCAT3(json_object_,jtype,_to_json_string)) -static inline struct json_object *json_object_new(enum json_type o_type, - size_t alloc_size, - json_object_to_json_string_fn *to_json_string); +#define JSON_OBJECT_NEW(jtype) \ + (struct JC_CONCAT(json_object_, jtype) *)json_object_new( \ + JC_CONCAT(json_type_, jtype), sizeof(struct JC_CONCAT(json_object_, jtype)), \ + &JC_CONCAT3(json_object_, jtype, _to_json_string)) + +static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, + json_object_to_json_string_fn *to_json_string); static void json_object_object_delete(struct json_object *jso_base); static void json_object_string_delete(struct json_object *jso); @@ -324,25 +324,16 @@ int json_object_put(struct json_object *jso) if (jso->_user_delete) jso->_user_delete(jso, jso->_userdata); - switch(jso->o_type) + switch (jso->o_type) { - case json_type_object: - json_object_object_delete(jso); - break; - case json_type_array: - json_object_array_delete(jso); - break; - case json_type_string: - json_object_string_delete(jso); - break; - default: - json_object_generic_delete(jso); - break; + case json_type_object: json_object_object_delete(jso); break; + case json_type_array: json_object_array_delete(jso); break; + case json_type_string: json_object_string_delete(jso); break; + default: json_object_generic_delete(jso); break; } return 1; } - /* generic object construction and destruction parts */ static void json_object_generic_delete(struct json_object *jso) @@ -355,9 +346,8 @@ static void json_object_generic_delete(struct json_object *jso) free(jso); } -static inline struct json_object *json_object_new(enum json_type o_type, - size_t alloc_size, - json_object_to_json_string_fn *to_json_string) +static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, + json_object_to_json_string_fn *to_json_string) { struct json_object *jso; @@ -370,7 +360,7 @@ static inline struct json_object *json_object_new(enum json_type o_type, jso->_to_json_string = to_json_string; jso->_pb = NULL; jso->_user_delete = NULL; - jso->_userdata= NULL; + jso->_userdata = NULL; //jso->... // Type-specific fields must be set by caller #ifdef REFCOUNT_DEBUG @@ -639,7 +629,6 @@ int json_object_object_length(const struct json_object *jso) return lh_table_length(JC_OBJECT_C(jso)->c_object); } - size_t json_c_object_sizeof(void) { return sizeof(struct json_object); @@ -664,7 +653,8 @@ json_bool json_object_object_get_ex(const struct json_object *jso, const char *k switch (jso->o_type) { case json_type_object: - return lh_table_lookup_ex(JC_OBJECT_C(jso)->c_object, (const void *)key, (void **)value); + return lh_table_lookup_ex(JC_OBJECT_C(jso)->c_object, (const void *)key, + (void **)value); default: if (value != NULL) *value = NULL; @@ -931,8 +921,7 @@ int json_object_int_inc(struct json_object *jso, int64_t val) case json_object_int_type_int64: if (val > 0 && jsoint->cint.c_int64 > INT64_MAX - val) { - jsoint->cint.c_uint64 = - (uint64_t)jsoint->cint.c_int64 + (uint64_t)val; + jsoint->cint.c_uint64 = (uint64_t)jsoint->cint.c_int64 + (uint64_t)val; jsoint->cint_type = json_object_int_type_uint64; } else if (val < 0 && jsoint->cint.c_int64 < INT64_MIN - val) @@ -1286,8 +1275,8 @@ static struct json_object *_json_object_new_string(const char *s, const size_t l // so we can stuff a pointer into pdata :( objsize += sizeof(void *) - len; - jso = (struct json_object_string *)json_object_new(json_type_string, objsize, - &json_object_string_to_json_string); + jso = (struct json_object_string *)json_object_new(json_type_string, objsize, + &json_object_string_to_json_string); if (!jso) return NULL; @@ -1325,8 +1314,10 @@ int json_object_get_string_len(const struct json_object *jso) switch (jso->o_type) { case json_type_string: + { len = JC_STRING_C(jso)->len; return (len < 0) ? -(ssize_t)len : len; + } default: return 0; } } @@ -1547,7 +1538,8 @@ static int json_object_all_values_equal(struct json_object *jso1, struct json_ob /* Iterate over jso1 keys and see if they exist and are equal in jso2 */ json_object_object_foreachC(jso1, iter) { - if (!lh_table_lookup_ex(JC_OBJECT(jso2)->c_object, (void *)iter.key, (void **)(void *)&sub)) + if (!lh_table_lookup_ex(JC_OBJECT(jso2)->c_object, (void *)iter.key, + (void **)(void *)&sub)) return 0; if (!json_object_equal(iter.val, sub)) return 0; @@ -1556,7 +1548,8 @@ static int json_object_all_values_equal(struct json_object *jso1, struct json_ob /* Iterate over jso2 keys to see if any exist that are not in jso1 */ json_object_object_foreachC(jso2, iter) { - if (!lh_table_lookup_ex(JC_OBJECT(jso1)->c_object, (void *)iter.key, (void **)(void *)&sub)) + if (!lh_table_lookup_ex(JC_OBJECT(jso1)->c_object, (void *)iter.key, + (void **)(void *)&sub)) return 0; } @@ -1590,8 +1583,7 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) return (int1->cint.c_int64 == int2->cint.c_int64); if (int1->cint.c_int64 < 0) return 0; - return ((uint64_t)int1->cint.c_int64 == - int2->cint.c_uint64); + return ((uint64_t)int1->cint.c_int64 == int2->cint.c_uint64); } // else jso1 is a uint64 if (int2->cint_type == json_object_int_type_uint64) @@ -1604,7 +1596,8 @@ int json_object_equal(struct json_object *jso1, struct json_object *jso2) case json_type_string: { return (json_object_get_string_len(jso1) == json_object_get_string_len(jso2) && - memcmp(get_string_component(jso1), get_string_component(jso2), json_object_get_string_len(jso1)) == 0); + memcmp(get_string_component(jso1), get_string_component(jso2), + json_object_get_string_len(jso1)) == 0); } case json_type_object: return json_object_all_values_equal(jso1, jso2); diff --git a/json_object_private.h b/json_object_private.h index d8dacd2..d1d782e 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -86,7 +86,7 @@ struct json_object_int struct json_object_string { struct json_object base; - ssize_t len; // Signed b/c negative lengths indicate data is a pointer + ssize_t len; // Signed b/c negative lengths indicate data is a pointer // Consider adding an "alloc" field here, if json_object_set_string calls // to expand the length of a string are common operations to perform. union From e26a1195f44a16348819dee2461ad6c1eb92a69b Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 20 Jun 2020 18:03:04 +0000 Subject: [PATCH 35/94] Add json_object_array_shrink() (and array_list_shrink()) and use it in json_tokener to minimize the amount of memory used. This results in a 39%-50% reduction in memory use (peak RSS, peak heap usage) on the jc-bench benchmark and 9% shorter runtime. Also add the json_object_new_array_ext, array_list_new2, and array_list_shrink functions. --- ChangeLog | 8 +++++++- arraylist.c | 29 ++++++++++++++++++++++++++++- arraylist.h | 27 +++++++++++++++++++++++++++ json_object.c | 13 ++++++++++++- json_object.h | 15 +++++++++++++++ json_tokener.c | 6 ++++++ 6 files changed, 95 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index afb5155..b785060 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,7 +4,7 @@ Next Release 0.15 Deprecated and removed features: -------------------------------- -...none yet... +* array_list_new() has been deprecated in favor of array_list_new2() Other changes -------------- @@ -19,6 +19,12 @@ Other changes less memory usage. Memory used just for json_object structures decreased 27%, so use cases with fewer arrays and/or strings would benefit more. +* Minimize memory usage in array handling in json_tokener by shrinking + arrays to the exact number of elements parsed. On bench/ benchmark: + 9% faster test time, 39%(max RSS)-50%(peak heap) less memory usage. + Add json_object_array_shrink() and array_list_shrink() functions. +* Add json_object_new_array_ext(int) and array_list_new_2(int) to allow + arrays to be allocated with the exact size needed, when known. *** diff --git a/arraylist.c b/arraylist.c index 3e7bfa8..c21b8e1 100644 --- a/arraylist.c +++ b/arraylist.c @@ -37,13 +37,18 @@ #include "arraylist.h" struct array_list *array_list_new(array_list_free_fn *free_fn) +{ + return array_list_new2(free_fn, ARRAY_LIST_DEFAULT_SIZE); +} + +struct array_list *array_list_new2(array_list_free_fn *free_fn, int initial_size) { struct array_list *arr; arr = (struct array_list *)malloc(sizeof(struct array_list)); if (!arr) return NULL; - arr->size = ARRAY_LIST_DEFAULT_SIZE; + arr->size = initial_size; arr->length = 0; arr->free_fn = free_fn; if (!(arr->array = (void **)malloc(arr->size * sizeof(void *)))) @@ -96,6 +101,26 @@ static int array_list_expand_internal(struct array_list *arr, size_t max) return 0; } +int array_list_shrink(struct array_list *arr, size_t empty_slots) +{ + void *t; + size_t new_size; + + new_size = arr->length + empty_slots; + if (new_size == arr->size) + return 0; + if (new_size > arr->size) + return array_list_expand_internal(arr, new_size); + if (new_size == 0) + new_size = 1; + + if (!(t = realloc(arr->array, new_size * sizeof(void *)))) + return -1; + arr->array = (void **)t; + arr->size = new_size; + return 0; +} + //static inline int _array_list_put_idx(struct array_list *arr, size_t idx, void *data) int array_list_put_idx(struct array_list *arr, size_t idx, void *data) { @@ -165,6 +190,8 @@ int array_list_del_idx(struct array_list *arr, size_t idx, size_t count) return -1; for (i = idx; i < stop; ++i) { + // Because put_idx can skip entries, we need to check if + // there's actually anything in each slot we're erasing. if (arr->array[i]) arr->free_fn(arr->array[i]); } diff --git a/arraylist.h b/arraylist.h index 3c4b1b2..2c0fe93 100644 --- a/arraylist.h +++ b/arraylist.h @@ -37,8 +37,27 @@ struct array_list }; typedef struct array_list array_list; +/** + * Allocate an array_list of the default size (32). + * @deprecated Use array_list_new2() instead. + */ extern struct array_list *array_list_new(array_list_free_fn *free_fn); +/** + * Allocate an array_list of the desired size. + * + * If possible, the size should be chosen to closely match + * the actual number of elements expected to be used. + * If the exact size is unknown, there are tradeoffs to be made: + * - too small - the array_list code will need to call realloc() more + * often (which might incur an additional memory copy). + * - too large - will waste memory, but that can be mitigated + * by calling array_list_shrink() once the final size is known. + * + * @see array_list_shrink + */ +extern struct array_list *array_list_new2(array_list_free_fn *free_fn, int initial_size); + extern void array_list_free(struct array_list *al); extern void *array_list_get_idx(struct array_list *al, size_t i); @@ -56,6 +75,14 @@ extern void *array_list_bsearch(const void **key, struct array_list *arr, extern int array_list_del_idx(struct array_list *arr, size_t idx, size_t count); + +/** + * Shrink the array list to just enough to fit the number of elements in it, + * plus empty_slots. + */ +extern int array_list_shrink(struct array_list *arr, size_t empty_slots); + + #ifdef __cplusplus } #endif diff --git a/json_object.c b/json_object.c index be84cb0..89439ab 100644 --- a/json_object.c +++ b/json_object.c @@ -1431,11 +1431,15 @@ static void json_object_array_delete(struct json_object *jso) } struct json_object *json_object_new_array(void) +{ + return json_object_new_array_ext(ARRAY_LIST_DEFAULT_SIZE); +} +struct json_object *json_object_new_array_ext(int initial_size) { struct json_object_array *jso = JSON_OBJECT_NEW(array); if (!jso) return NULL; - jso->c_array = array_list_new(&json_object_array_entry_free); + jso->c_array = array_list_new2(&json_object_array_entry_free, initial_size); if (jso->c_array == NULL) { free(jso); @@ -1523,6 +1527,13 @@ static int json_array_equal(struct json_object *jso1, struct json_object *jso2) return 1; } +int json_object_array_shrink(struct json_object *jso, int empty_slots) +{ + if (empty_slots < 0) + json_abort("json_object_array_shrink called with negative empty_slots"); + return array_list_shrink(JC_ARRAY(jso)->c_array, empty_slots); +} + struct json_object *json_object_new_null(void) { return NULL; diff --git a/json_object.h b/json_object.h index 7c0d1f2..5f2f64c 100644 --- a/json_object.h +++ b/json_object.h @@ -500,10 +500,16 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key /* Array type methods */ /** Create a new empty json_object of type json_type_array + * If you know the array size you'll need ahead of time, use + * json_object_new_array_ext() instead. + * @see json_object_new_array_ext() + * @see json_object_array_shrink() * @returns a json_object of type json_type_array */ JSON_EXPORT struct json_object *json_object_new_array(void); +JSON_EXPORT struct json_object *json_object_new_array_ext(int initial_size); + /** Get the arraylist of a json_object of type json_type_array * @param obj the json_object instance * @returns an arraylist @@ -595,6 +601,15 @@ JSON_EXPORT struct json_object *json_object_array_get_idx(const struct json_obje */ JSON_EXPORT int json_object_array_del_idx(struct json_object *obj, size_t idx, size_t count); +/** + * Shrink the internal memory allocation of the array to just + * enough to fit the number of elements in it, plus empty_slots. + * + * @param jso the json_object instance, must be json_type_array + * @param empty_slots the number of empty slots to leave allocated + */ +JSON_EXPORT int json_object_array_shrink(struct json_object *jso, int empty_slots); + /* json_bool type methods */ /** Create a new empty json_object of type json_type_boolean diff --git a/json_tokener.c b/json_tokener.c index 0373d6f..9aa86a9 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -964,6 +964,9 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * case json_tokener_state_array: if (c == ']') { + // Minimize memory usage; assume parsed objs are unlikely to be changed + json_object_array_shrink(current, 0); + if (state == json_tokener_state_array_after_sep && (tok->flags & JSON_TOKENER_STRICT)) { @@ -997,6 +1000,9 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * case json_tokener_state_array_sep: if (c == ']') { + // Minimize memory usage; assume parsed objs are unlikely to be changed + json_object_array_shrink(current, 0); + saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; } From 50179fb09f5d317e7192c781ca4a6b039d7818ae Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 21 Jun 2020 02:35:42 +0000 Subject: [PATCH 36/94] Update the json_tokener_parse_ex() docs to clarify that the final '\0' character is to be included in length passed in. --- json_tokener.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/json_tokener.h b/json_tokener.h index 8afa6ec..4e17dff 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -220,8 +220,8 @@ JSON_EXPORT void json_tokener_set_flags(struct json_tokener *tok, int flags); * * If json_tokener_parse_ex() returns NULL and the error is anything other than * json_tokener_continue, a fatal error has occurred and parsing must be - * halted. Then, the tok object must not be reused until json_tokener_reset() is - * called. + * halted. Then, the tok object must not be reused until json_tokener_reset() + * is called. * * When a valid JSON value is parsed, a non-NULL json_object will be * returned, with a reference count of one which belongs to the caller. Also, @@ -234,13 +234,18 @@ JSON_EXPORT void json_tokener_set_flags(struct json_tokener *tok, int flags); * error or to handle the additional characters, perhaps by parsing another * json value starting from that point. * + * If the caller knows that they are at the end of their input, the length + * passed MUST include the final '\0' character, so values with no inherent + * end (i.e. numbers) can be properly parsed, rather than just returning + * json_tokener_continue. + * * Extra characters can be detected by comparing the value returned by * json_tokener_get_parse_end() against * the length of the last len parameter passed in. * * The tokener does \b not maintain an internal buffer so the caller is - * responsible for calling json_tokener_parse_ex with an appropriate str - * parameter starting with the extra characters. + * responsible for a subsequent call to json_tokener_parse_ex with an + * appropriate str parameter starting with the extra characters. * * This interface is presently not 64-bit clean due to the int len argument * so the function limits the maximum string size to INT32_MAX (2GB). @@ -256,6 +261,8 @@ enum json_tokener_error jerr; do { mystring = ... // get JSON string, e.g. read from file, etc... stringlen = strlen(mystring); + if (end_of_input) + stringlen++; // Include the '\0' if we know we're at the end of input jobj = json_tokener_parse_ex(tok, mystring, stringlen); } while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue); if (jerr != json_tokener_success) From 36118b681ea3b8e99735beee73cbd25a63e942cd Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 21 Jun 2020 03:10:55 +0000 Subject: [PATCH 37/94] Rearrange the json_tokener_state_escape_unicode case in json_tokener to simplify the code slightly and make it a bit easier to understand. While here, drop the utf8_replacement_char that is unnecesarily added if we run out of input in the middle of a unicode escape. No other functional changes (yet). --- json_tokener.c | 335 +++++++++++++++++++++++++------------------------ json_tokener.h | 2 +- 2 files changed, 172 insertions(+), 165 deletions(-) diff --git a/json_tokener.c b/json_tokener.c index 2a73ce2..15ddd17 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -223,7 +223,7 @@ struct json_object *json_tokener_parse_verbose(const char *str, enum json_tokene /* PEEK_CHAR(dest, tok) macro: * Peeks at the current char and stores it in dest. * Returns 1 on success, sets tok->err and returns 0 if no more chars. - * Implicit inputs: str, len vars + * Implicit inputs: str, len, nBytesp vars */ #define PEEK_CHAR(dest, tok) \ (((tok)->char_offset == len) \ @@ -633,175 +633,182 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * /* Handle a 4-byte sequence, or two sequences if a surrogate pair */ while (1) { - if (c && strchr(json_hex_chars, c)) - { - tok->ucs_char += ((unsigned int)jt_hexdigit(c) - << ((3 - tok->st_pos++) * 4)); - if (tok->st_pos == 4) - { - unsigned char unescaped_utf[4]; - - if (tok->got_hi_surrogate) - { - if (IS_LOW_SURROGATE(tok->ucs_char)) - { - /* remove the utf8_replacement_char */ - /* which may generate during */ - /* parsing the high surrogate pair. */ - if (!strcmp( - tok->pb->buf, - (char *) - utf8_replacement_char)) - { - printbuf_reset(tok->pb); - } - /* Recalculate the ucs_char, then fall thru to process normally */ - tok->ucs_char = - DECODE_SURROGATE_PAIR( - tok->got_hi_surrogate, - tok->ucs_char); - } - else - { - /* Hi surrogate was not followed by a low surrogate */ - /* Replace the hi and process the rest normally */ - printbuf_memappend_fast( - tok->pb, - (char *)utf8_replacement_char, - 3); - } - tok->got_hi_surrogate = 0; - } - - if (tok->ucs_char < 0x80) - { - unescaped_utf[0] = tok->ucs_char; - printbuf_memappend_fast( - tok->pb, (char *)unescaped_utf, 1); - } - else if (tok->ucs_char < 0x800) - { - unescaped_utf[0] = - 0xc0 | (tok->ucs_char >> 6); - unescaped_utf[1] = - 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast( - tok->pb, (char *)unescaped_utf, 2); - } - else if (IS_HIGH_SURROGATE(tok->ucs_char)) - { - /* Got a high surrogate. Remember it and look for - * the beginning of another sequence, which - * should be the low surrogate. - */ - tok->got_hi_surrogate = tok->ucs_char; - /* Not at end, and the next two chars should be "\u" */ - if ((len == -1 || - len > (tok->char_offset + 2)) && - // str[0] != '0' && // implied by json_hex_chars, above. - (str[1] == '\\') && (str[2] == 'u')) - { - /* Advance through the 16 bit surrogate, and move - * on to the next sequence. The next step is to - * process the following characters. - */ - if (!ADVANCE_CHAR(str, tok) || - !ADVANCE_CHAR(str, tok)) - { - printbuf_memappend_fast( - tok->pb, - (char *) - utf8_replacement_char, - 3); - } - /* Advance to the first char of the next sequence and - * continue processing with the next sequence. - */ - if (!ADVANCE_CHAR(str, tok) || - !PEEK_CHAR(c, tok)) - { - printbuf_memappend_fast( - tok->pb, - (char *) - utf8_replacement_char, - 3); - tok->ucs_char = 0; - tok->st_pos = 0; - goto out; - } - tok->ucs_char = 0; - tok->st_pos = 0; - /* other json_tokener_state_escape_unicode */ - continue; - } - else - { - /* Got a high surrogate without another sequence following - * it. Put a replacement char in for the hi surrogate - * and pretend we finished. - */ - printbuf_memappend_fast( - tok->pb, - (char *)utf8_replacement_char, - 3); - } - } - else if (IS_LOW_SURROGATE(tok->ucs_char)) - { - /* Got a low surrogate not preceded by a high */ - printbuf_memappend_fast( - tok->pb, (char *)utf8_replacement_char, - 3); - } - else if (tok->ucs_char < 0x10000) - { - unescaped_utf[0] = - 0xe0 | (tok->ucs_char >> 12); - unescaped_utf[1] = - 0x80 | ((tok->ucs_char >> 6) & 0x3f); - unescaped_utf[2] = - 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast( - tok->pb, (char *)unescaped_utf, 3); - } - else if (tok->ucs_char < 0x110000) - { - unescaped_utf[0] = - 0xf0 | ((tok->ucs_char >> 18) & 0x07); - unescaped_utf[1] = - 0x80 | ((tok->ucs_char >> 12) & 0x3f); - unescaped_utf[2] = - 0x80 | ((tok->ucs_char >> 6) & 0x3f); - unescaped_utf[3] = - 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast( - tok->pb, (char *)unescaped_utf, 4); - } - else - { - /* Don't know what we got--insert the replacement char */ - printbuf_memappend_fast( - tok->pb, (char *)utf8_replacement_char, - 3); - } - state = saved_state; - break; - } - } - else + if (!c || !strchr(json_hex_chars, c)) { tok->err = json_tokener_error_parse_string; goto out; } - if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) + tok->ucs_char |= ((unsigned int)jt_hexdigit(c) + << ((3 - tok->st_pos) * 4)); + tok->st_pos++; + if (tok->st_pos < 4) { - /* Clean up any pending chars */ - if (tok->got_hi_surrogate && - strcmp(tok->pb->buf, (char *)utf8_replacement_char)) - printbuf_memappend_fast( - tok->pb, (char *)utf8_replacement_char, 3); - goto out; + ADVANCE_CHAR(str, tok); + if (!PEEK_CHAR(c, tok)) + { + /* + * We're out of characters in the current call to + * json_tokener_parse(), but a subsequent call might + * provide us with more, so leave our current state + * as-is (including tok->high_surrogate) and return. + */ + goto out; + } + continue; } + + /* Now, we have a full \uNNNN sequence in tok->ucs_char */ + + if (tok->high_surrogate) + { + if (IS_LOW_SURROGATE(tok->ucs_char)) + { + /* remove the utf8_replacement_char */ + /* which may generate during */ + /* parsing the high surrogate pair. */ + if (!strcmp( + tok->pb->buf, + (char *) + utf8_replacement_char)) + { + printbuf_reset(tok->pb); + } + /* Recalculate the ucs_char, then fall thru to process normally */ + tok->ucs_char = + DECODE_SURROGATE_PAIR( + tok->high_surrogate, + tok->ucs_char); + } + else + { + /* High surrogate was not followed by a low surrogate + * Replace the high and process the rest normally + */ + printbuf_memappend_fast( + tok->pb, + (char *)utf8_replacement_char, + 3); + } + tok->high_surrogate = 0; + } + + if (tok->ucs_char < 0x80) + { + unsigned char unescaped_utf[1]; + unescaped_utf[0] = tok->ucs_char; + printbuf_memappend_fast( + tok->pb, (char *)unescaped_utf, 1); + } + else if (tok->ucs_char < 0x800) + { + unsigned char unescaped_utf[2]; + unescaped_utf[0] = + 0xc0 | (tok->ucs_char >> 6); + unescaped_utf[1] = + 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast( + tok->pb, (char *)unescaped_utf, 2); + } + else if (IS_HIGH_SURROGATE(tok->ucs_char)) + { + /* Got a high surrogate. Remember it and look for + * the beginning of another \uNNNN sequence, which + * should be the low surrogate. + */ + tok->high_surrogate = tok->ucs_char; + /* Not at end, and the next two chars should be "\u" */ + if ((len == -1 || + len > (tok->char_offset + 2)) && + // str[0] != '0' && // implied by json_hex_chars, above. + (str[1] == '\\') && (str[2] == 'u')) + { + /* Advance through the 16 bit surrogate, and move + * on to the next sequence. The next step is to + * process the following characters. + */ + if (!ADVANCE_CHAR(str, tok) || + !ADVANCE_CHAR(str, tok)) + { + printbuf_memappend_fast( + tok->pb, + (char *) + utf8_replacement_char, + 3); + } + /* Advance to the first char of the next sequence and + * continue processing with the next sequence. + */ + if (!ADVANCE_CHAR(str, tok) || + !PEEK_CHAR(c, tok)) + { + printbuf_memappend_fast( + tok->pb, + (char *) + utf8_replacement_char, + 3); + tok->ucs_char = 0; + tok->st_pos = 0; + goto out; + } + tok->ucs_char = 0; + tok->st_pos = 0; + /* other json_tokener_state_escape_unicode */ + continue; + } + else + { + /* Got a high surrogate without another sequence following + * it. Put a replacement char in for the high surrogate + * and pretend we finished. + */ + printbuf_memappend_fast( + tok->pb, + (char *)utf8_replacement_char, + 3); + } + } + else if (IS_LOW_SURROGATE(tok->ucs_char)) + { + /* Got a low surrogate not preceded by a high */ + printbuf_memappend_fast( + tok->pb, (char *)utf8_replacement_char, + 3); + } + else if (tok->ucs_char < 0x10000) + { + unsigned char unescaped_utf[3]; + unescaped_utf[0] = + 0xe0 | (tok->ucs_char >> 12); + unescaped_utf[1] = + 0x80 | ((tok->ucs_char >> 6) & 0x3f); + unescaped_utf[2] = + 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast( + tok->pb, (char *)unescaped_utf, 3); + } + else if (tok->ucs_char < 0x110000) + { + unsigned char unescaped_utf[4]; + unescaped_utf[0] = + 0xf0 | ((tok->ucs_char >> 18) & 0x07); + unescaped_utf[1] = + 0x80 | ((tok->ucs_char >> 12) & 0x3f); + unescaped_utf[2] = + 0x80 | ((tok->ucs_char >> 6) & 0x3f); + unescaped_utf[3] = + 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast( + tok->pb, (char *)unescaped_utf, 4); + } + else + { + /* Don't know what we got--insert the replacement char */ + printbuf_memappend_fast( + tok->pb, (char *)utf8_replacement_char, + 3); + } + state = saved_state; // i.e. _state_string or _object_field + break; } } break; diff --git a/json_tokener.h b/json_tokener.h index 4e17dff..421ef14 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -111,7 +111,7 @@ struct json_tokener * @deprecated See json_tokener_get_error() instead. */ enum json_tokener_error err; - unsigned int ucs_char, got_hi_surrogate; + unsigned int ucs_char, high_surrogate; char quote_char; struct json_tokener_srec *stack; int flags; From 197e3724641f26a54546c66ecdf6bf950735e05b Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 21 Jun 2020 17:36:38 +0000 Subject: [PATCH 38/94] In test_parse, fix lengths passed during a couple of incremental tests. Add an optional way to use an incremental chunk size ($TEST_PARSE_CHUNKSIZE) for all of the single_basic_parse tests, in additional to the regular way. --- tests/test_parse.c | 53 ++++++++++++++++++++++++++++++++++++--- tests/test_parse.expected | 4 +-- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/tests/test_parse.c b/tests/test_parse.c index 42b2fdf..57d584c 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -33,6 +33,47 @@ int main(void) static json_c_visit_userfunc clear_serializer; static void do_clear_serializer(json_object *jso); +static void single_incremental_parse(const char *test_string, int clear_serializer) +{ + int ii; + int chunksize = atoi(getenv("TEST_PARSE_CHUNKSIZE")); + struct json_tokener *tok; + enum json_tokener_error jerr; + json_object *all_at_once_obj, *new_obj; + const char *all_at_once_str, *new_str; + + all_at_once_obj = json_tokener_parse(test_string); + if (clear_serializer) + do_clear_serializer(all_at_once_obj); + all_at_once_str = json_object_to_json_string(all_at_once_obj); + + tok = json_tokener_new(); + int test_string_len = strlen(test_string) + 1; // Including '\0' ! + for (ii = 0; ii < test_string_len; ii += chunksize) + { + int len_to_parse = chunksize; + if (ii + chunksize > test_string_len) + len_to_parse = test_string_len - ii; + + if (getenv("TEST_PARSE_DEBUG") != NULL) + printf(" chunk: %.*s\n", len_to_parse, &test_string[ii]); + new_obj = json_tokener_parse_ex(tok, &test_string[ii], len_to_parse); + jerr = json_tokener_get_error(tok); + if (jerr != json_tokener_continue || new_obj) + break; + } + if (clear_serializer && new_obj) + do_clear_serializer(new_obj); + new_str = json_object_to_json_string(new_obj); + + if (strcmp(all_at_once_str, new_str) != 0) + { + printf("ERROR: failed to parse (%s) in %d byte chunks: %s != %s\n", + test_string, chunksize, all_at_once_str, new_str); + } + json_tokener_free(tok); +} + static void single_basic_parse(const char *test_string, int clear_serializer) { json_object *new_obj; @@ -42,6 +83,9 @@ static void single_basic_parse(const char *test_string, int clear_serializer) do_clear_serializer(new_obj); printf("new_obj.to_string(%s)=%s\n", test_string, json_object_to_json_string(new_obj)); json_object_put(new_obj); + + if (getenv("TEST_PARSE_CHUNKSIZE") != NULL) + single_incremental_parse(test_string, clear_serializer); } static void test_basic_parse() { @@ -353,14 +397,17 @@ struct incremental_step * the next few tests check that parsing multiple sequential * json objects in the input works as expected */ - {"null123", 9, 4, json_tokener_success, 0}, + {"null123", 8, 4, json_tokener_success, 0}, {&"null123"[4], 4, 3, json_tokener_success, 1}, - {"nullx", 5, 4, json_tokener_success, 0}, + {"nullx", 6, 4, json_tokener_success, 0}, {&"nullx"[4], 2, 0, json_tokener_error_parse_unexpected, 1}, {"{\"a\":1}{\"b\":2}", 15, 7, json_tokener_success, 0}, {&"{\"a\":1}{\"b\":2}"[7], 8, 7, json_tokener_success, 1}, - /* Some bad formatting. Check we get the correct error status */ + /* Some bad formatting. Check we get the correct error status + * XXX this means we can't have two numbers in the incremental parse + * XXX stream with the second one being a negative number! + */ {"2015-01-15", 10, 4, json_tokener_error_parse_number, 1}, /* Strings have a well defined end point, so we can stop at the quote */ diff --git a/tests/test_parse.expected b/tests/test_parse.expected index df74fbd..a4b3393 100644 --- a/tests/test_parse.expected +++ b/tests/test_parse.expected @@ -184,9 +184,9 @@ json_tokener_parse_ex(tok, noodle , 7) ... OK: got correct error: null ex json_tokener_parse_ex(tok, naodle , 7) ... OK: got correct error: null expected json_tokener_parse_ex(tok, track , 6) ... OK: got correct error: boolean expected json_tokener_parse_ex(tok, fail , 5) ... OK: got correct error: boolean expected -json_tokener_parse_ex(tok, null123 , 9) ... OK: got object of type [null]: null +json_tokener_parse_ex(tok, null123 , 8) ... OK: got object of type [null]: null json_tokener_parse_ex(tok, 123 , 4) ... OK: got object of type [int]: 123 -json_tokener_parse_ex(tok, nullx , 5) ... OK: got object of type [null]: null +json_tokener_parse_ex(tok, nullx , 6) ... OK: got object of type [null]: null json_tokener_parse_ex(tok, x , 2) ... OK: got correct error: unexpected character json_tokener_parse_ex(tok, {"a":1}{"b":2}, 15) ... OK: got object of type [object]: { "a": 1 } json_tokener_parse_ex(tok, {"b":2} , 8) ... OK: got object of type [object]: { "b": 2 } From a68566bf6a2b44b5932072e85261a971097bc0a9 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 21 Jun 2020 18:17:40 +0000 Subject: [PATCH 39/94] Issue #616: Change the parsing of surrogate pairs in unicode escapes so it uses a couple of additional states instead of assuming the low surrogate is already present, to ensure that we correctly handle various cases of incremental parsing. --- ChangeLog | 2 + json_tokener.c | 306 ++++++++++++++++++-------------------- json_tokener.h | 2 + tests/test_parse.c | 26 +++- tests/test_parse.expected | 8 +- 5 files changed, 172 insertions(+), 172 deletions(-) diff --git a/ChangeLog b/ChangeLog index b785060..0ca4b59 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,6 +25,8 @@ Other changes Add json_object_array_shrink() and array_list_shrink() functions. * Add json_object_new_array_ext(int) and array_list_new_2(int) to allow arrays to be allocated with the exact size needed, when known. +* Parsing of surrogate pairs in unicode escapes now properly handles + incremental parsing. *** diff --git a/json_tokener.c b/json_tokener.c index 15ddd17..82cb8d9 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -295,7 +295,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * } #endif - while (PEEK_CHAR(c, tok)) + while (PEEK_CHAR(c, tok)) // Note: c might be '\0' ! { redo_char: @@ -628,9 +628,11 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * } break; + // =================================================== + case json_tokener_state_escape_unicode: { - /* Handle a 4-byte sequence, or two sequences if a surrogate pair */ + /* Handle a 4-byte \uNNNN sequence, or two sequences if a surrogate pair */ while (1) { if (!c || !strchr(json_hex_chars, c)) @@ -638,181 +640,153 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * tok->err = json_tokener_error_parse_string; goto out; } - tok->ucs_char |= ((unsigned int)jt_hexdigit(c) - << ((3 - tok->st_pos) * 4)); + tok->ucs_char |= + ((unsigned int)jt_hexdigit(c) << ((3 - tok->st_pos) * 4)); tok->st_pos++; - if (tok->st_pos < 4) - { - ADVANCE_CHAR(str, tok); - if (!PEEK_CHAR(c, tok)) - { - /* - * We're out of characters in the current call to - * json_tokener_parse(), but a subsequent call might - * provide us with more, so leave our current state - * as-is (including tok->high_surrogate) and return. - */ - goto out; - } - continue; - } + if (tok->st_pos >= 4) + break; - /* Now, we have a full \uNNNN sequence in tok->ucs_char */ - - if (tok->high_surrogate) + ADVANCE_CHAR(str, tok); + if (!PEEK_CHAR(c, tok)) { - if (IS_LOW_SURROGATE(tok->ucs_char)) - { - /* remove the utf8_replacement_char */ - /* which may generate during */ - /* parsing the high surrogate pair. */ - if (!strcmp( - tok->pb->buf, - (char *) - utf8_replacement_char)) - { - printbuf_reset(tok->pb); - } - /* Recalculate the ucs_char, then fall thru to process normally */ - tok->ucs_char = - DECODE_SURROGATE_PAIR( - tok->high_surrogate, - tok->ucs_char); - } - else - { - /* High surrogate was not followed by a low surrogate - * Replace the high and process the rest normally - */ - printbuf_memappend_fast( - tok->pb, - (char *)utf8_replacement_char, - 3); - } - tok->high_surrogate = 0; - } - - if (tok->ucs_char < 0x80) - { - unsigned char unescaped_utf[1]; - unescaped_utf[0] = tok->ucs_char; - printbuf_memappend_fast( - tok->pb, (char *)unescaped_utf, 1); - } - else if (tok->ucs_char < 0x800) - { - unsigned char unescaped_utf[2]; - unescaped_utf[0] = - 0xc0 | (tok->ucs_char >> 6); - unescaped_utf[1] = - 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast( - tok->pb, (char *)unescaped_utf, 2); - } - else if (IS_HIGH_SURROGATE(tok->ucs_char)) - { - /* Got a high surrogate. Remember it and look for - * the beginning of another \uNNNN sequence, which - * should be the low surrogate. + /* + * We're out of characters in the current call to + * json_tokener_parse(), but a subsequent call might + * provide us with more, so leave our current state + * as-is (including tok->high_surrogate) and return. */ - tok->high_surrogate = tok->ucs_char; - /* Not at end, and the next two chars should be "\u" */ - if ((len == -1 || - len > (tok->char_offset + 2)) && - // str[0] != '0' && // implied by json_hex_chars, above. - (str[1] == '\\') && (str[2] == 'u')) - { - /* Advance through the 16 bit surrogate, and move - * on to the next sequence. The next step is to - * process the following characters. - */ - if (!ADVANCE_CHAR(str, tok) || - !ADVANCE_CHAR(str, tok)) - { - printbuf_memappend_fast( - tok->pb, - (char *) - utf8_replacement_char, - 3); - } - /* Advance to the first char of the next sequence and - * continue processing with the next sequence. - */ - if (!ADVANCE_CHAR(str, tok) || - !PEEK_CHAR(c, tok)) - { - printbuf_memappend_fast( - tok->pb, - (char *) - utf8_replacement_char, - 3); - tok->ucs_char = 0; - tok->st_pos = 0; - goto out; - } - tok->ucs_char = 0; - tok->st_pos = 0; - /* other json_tokener_state_escape_unicode */ - continue; - } - else - { - /* Got a high surrogate without another sequence following - * it. Put a replacement char in for the high surrogate - * and pretend we finished. - */ - printbuf_memappend_fast( - tok->pb, - (char *)utf8_replacement_char, - 3); - } + goto out; } - else if (IS_LOW_SURROGATE(tok->ucs_char)) + } + tok->st_pos = 0; + + /* Now, we have a full \uNNNN sequence in tok->ucs_char */ + + /* If the *previous* sequence was a high surrogate ... */ + if (tok->high_surrogate) + { + if (IS_LOW_SURROGATE(tok->ucs_char)) { - /* Got a low surrogate not preceded by a high */ - printbuf_memappend_fast( - tok->pb, (char *)utf8_replacement_char, - 3); - } - else if (tok->ucs_char < 0x10000) - { - unsigned char unescaped_utf[3]; - unescaped_utf[0] = - 0xe0 | (tok->ucs_char >> 12); - unescaped_utf[1] = - 0x80 | ((tok->ucs_char >> 6) & 0x3f); - unescaped_utf[2] = - 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast( - tok->pb, (char *)unescaped_utf, 3); - } - else if (tok->ucs_char < 0x110000) - { - unsigned char unescaped_utf[4]; - unescaped_utf[0] = - 0xf0 | ((tok->ucs_char >> 18) & 0x07); - unescaped_utf[1] = - 0x80 | ((tok->ucs_char >> 12) & 0x3f); - unescaped_utf[2] = - 0x80 | ((tok->ucs_char >> 6) & 0x3f); - unescaped_utf[3] = - 0x80 | (tok->ucs_char & 0x3f); - printbuf_memappend_fast( - tok->pb, (char *)unescaped_utf, 4); + /* Recalculate the ucs_char, then fall thru to process normally */ + tok->ucs_char = DECODE_SURROGATE_PAIR(tok->high_surrogate, + tok->ucs_char); } else { - /* Don't know what we got--insert the replacement char */ - printbuf_memappend_fast( - tok->pb, (char *)utf8_replacement_char, - 3); + /* High surrogate was not followed by a low surrogate + * Replace the high and process the rest normally + */ + printbuf_memappend_fast(tok->pb, + (char *)utf8_replacement_char, 3); } - state = saved_state; // i.e. _state_string or _object_field + tok->high_surrogate = 0; + } + + if (tok->ucs_char < 0x80) + { + unsigned char unescaped_utf[1]; + unescaped_utf[0] = tok->ucs_char; + printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 1); + } + else if (tok->ucs_char < 0x800) + { + unsigned char unescaped_utf[2]; + unescaped_utf[0] = 0xc0 | (tok->ucs_char >> 6); + unescaped_utf[1] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 2); + } + else if (IS_HIGH_SURROGATE(tok->ucs_char)) + { + /* + * The next two characters should be \u, HOWEVER, + * we can't simply peek ahead here, because the + * characters we need might not be passed to us + * until a subsequent call to json_tokener_parse. + * Instead, transition throug a couple of states. + * (now): + * _escape_unicode => _unicode_need_escape + * (see a '\\' char): + * _unicode_need_escape => _unicode_need_u + * (see a 'u' char): + * _unicode_need_u => _escape_unicode + * ...and we'll end up back around here. + */ + tok->high_surrogate = tok->ucs_char; + tok->ucs_char = 0; + state = json_tokener_state_escape_unicode_need_escape; break; } + else if (IS_LOW_SURROGATE(tok->ucs_char)) + { + /* Got a low surrogate not preceded by a high */ + printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3); + } + else if (tok->ucs_char < 0x10000) + { + unsigned char unescaped_utf[3]; + unescaped_utf[0] = 0xe0 | (tok->ucs_char >> 12); + unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); + unescaped_utf[2] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 3); + } + else if (tok->ucs_char < 0x110000) + { + unsigned char unescaped_utf[4]; + unescaped_utf[0] = 0xf0 | ((tok->ucs_char >> 18) & 0x07); + unescaped_utf[1] = 0x80 | ((tok->ucs_char >> 12) & 0x3f); + unescaped_utf[2] = 0x80 | ((tok->ucs_char >> 6) & 0x3f); + unescaped_utf[3] = 0x80 | (tok->ucs_char & 0x3f); + printbuf_memappend_fast(tok->pb, (char *)unescaped_utf, 4); + } + else + { + /* Don't know what we got--insert the replacement char */ + printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3); + } + state = saved_state; // i.e. _state_string or _state_object_field } break; + case json_tokener_state_escape_unicode_need_escape: + // We get here after processing a high_surrogate + // require a '\\' char + if (!c || c != '\\') + { + /* Got a high surrogate without another sequence following + * it. Put a replacement char in for the high surrogate + * and pop back up to _state_string or _state_object_field. + */ + printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3); + tok->high_surrogate = 0; + tok->ucs_char = 0; + tok->st_pos = 0; + state = saved_state; + goto redo_char; + } + state = json_tokener_state_escape_unicode_need_u; + break; + + case json_tokener_state_escape_unicode_need_u: + /* We already had a \ char, check that it's \u */ + if (!c || c != 'u') + { + /* Got a high surrogate with some non-unicode escape + * sequence following it. + * Put a replacement char in for the high surrogate + * and handle the escape sequence normally. + */ + printbuf_memappend_fast(tok->pb, (char *)utf8_replacement_char, 3); + tok->high_surrogate = 0; + tok->ucs_char = 0; + tok->st_pos = 0; + state = json_tokener_state_string_escape; + goto redo_char; + } + state = json_tokener_state_escape_unicode; + break; + + // =================================================== + case json_tokener_state_boolean: { int size1, size2; @@ -1146,8 +1120,9 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * } break; } - if (!ADVANCE_CHAR(str, tok)) - goto out; + (void)ADVANCE_CHAR(str, tok); + if (!c) // This is the char *before* advancing + break; } /* while(PEEK_CHAR) */ out: @@ -1156,7 +1131,8 @@ out: tok->err = json_tokener_error_parse_utf8_string; } if (c && (state == json_tokener_state_finish) && (tok->depth == 0) && - (tok->flags & (JSON_TOKENER_STRICT|JSON_TOKENER_ALLOW_TRAILING_CHARS)) == JSON_TOKENER_STRICT) + (tok->flags & (JSON_TOKENER_STRICT | JSON_TOKENER_ALLOW_TRAILING_CHARS)) == + JSON_TOKENER_STRICT) { /* unexpected char after JSON data */ tok->err = json_tokener_error_parse_unexpected; diff --git a/json_tokener.h b/json_tokener.h index 421ef14..c680603 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -59,6 +59,8 @@ enum json_tokener_state json_tokener_state_string, json_tokener_state_string_escape, json_tokener_state_escape_unicode, + json_tokener_state_escape_unicode_need_escape, + json_tokener_state_escape_unicode_need_u, json_tokener_state_boolean, json_tokener_state_number, json_tokener_state_array, diff --git a/tests/test_parse.c b/tests/test_parse.c index 57d584c..da82b51 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -68,8 +68,8 @@ static void single_incremental_parse(const char *test_string, int clear_serializ if (strcmp(all_at_once_str, new_str) != 0) { - printf("ERROR: failed to parse (%s) in %d byte chunks: %s != %s\n", - test_string, chunksize, all_at_once_str, new_str); + printf("ERROR: failed to parse (%s) in %d byte chunks: %s != %s\n", test_string, + chunksize, all_at_once_str, new_str); } json_tokener_free(tok); } @@ -193,8 +193,8 @@ static void test_utf8_parse() // json_tokener_parse doesn't support checking for byte order marks. // It's the responsibility of the caller to detect and skip a BOM. // Both of these checks return null. - char* utf8_bom = "\xEF\xBB\xBF"; - char* utf8_bom_and_chars = "\xEF\xBB\xBF{}"; + char *utf8_bom = "\xEF\xBB\xBF"; + char *utf8_bom_and_chars = "\xEF\xBB\xBF{}"; single_basic_parse(utf8_bom, 0); single_basic_parse(utf8_bom_and_chars, 0); } @@ -245,7 +245,7 @@ struct incremental_step int char_offset; enum json_tokener_error expected_error; int reset_tokener; /* Set to 1 to call json_tokener_reset() after parsing */ - int tok_flags; /* JSON_TOKENER_* flags to pass to json_tokener_set_flags() */ + int tok_flags; /* JSON_TOKENER_* flags to pass to json_tokener_set_flags() */ } incremental_steps[] = { /* Check that full json messages can be parsed, both w/ and w/o a reset */ @@ -268,7 +268,11 @@ struct incremental_step {"\": {\"bar", -1, -1, json_tokener_continue, 0}, {"\":13}}", -1, -1, json_tokener_success, 1}, - /* Check the UTF-16 surrogate pair */ + /* Check the UTF-16 surrogate pair handling in various ways. + * Note: \ud843\udd1e is u+1D11E, Musical Symbol G Clef + * Your terminal may not display these correctly, in particular + * PuTTY doesn't currently show this character. + */ /* parse one char at every time */ {"\"\\", -1, -1, json_tokener_continue, 0}, {"u", -1, -1, json_tokener_continue, 0}, @@ -296,6 +300,16 @@ struct incremental_step {"udd1e\"", -1, -1, json_tokener_success, 1}, {"\"\\ud834\\u", -1, -1, json_tokener_continue, 0}, {"dd1e\"", -1, -1, json_tokener_success, 1}, + {"\"fff \\ud834\\ud", -1, -1, json_tokener_continue, 0}, + {"d1e bar\"", -1, -1, json_tokener_success, 1}, + {"\"fff \\ud834\\udd", -1, -1, json_tokener_continue, 0}, + {"1e bar\"", -1, -1, json_tokener_success, 1}, + + /* \ud83d\ude00 is U+1F600, Grinning Face + * Displays fine in PuTTY, though you may need "less -r" + */ + {"\"fff \\ud83d\\ude", -1, -1, json_tokener_continue, 0}, + {"00 bar\"", -1, -1, json_tokener_success, 1}, /* Check that json_tokener_reset actually resets */ {"{ \"foo", -1, -1, json_tokener_continue, 1}, diff --git a/tests/test_parse.expected b/tests/test_parse.expected index a4b3393..6ed5520 100644 --- a/tests/test_parse.expected +++ b/tests/test_parse.expected @@ -124,6 +124,12 @@ json_tokener_parse_ex(tok, "\ud834\ , 8) ... OK: got correct error: continu json_tokener_parse_ex(tok, udd1e" , 6) ... OK: got object of type [string]: "ð„ž" json_tokener_parse_ex(tok, "\ud834\u , 9) ... OK: got correct error: continue json_tokener_parse_ex(tok, dd1e" , 5) ... OK: got object of type [string]: "ð„ž" +json_tokener_parse_ex(tok, "fff \ud834\ud, 14) ... OK: got correct error: continue +json_tokener_parse_ex(tok, d1e bar" , 8) ... OK: got object of type [string]: "fff ð„ž bar" +json_tokener_parse_ex(tok, "fff \ud834\udd, 15) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 1e bar" , 7) ... OK: got object of type [string]: "fff ð„ž bar" +json_tokener_parse_ex(tok, "fff \ud83d\ude, 15) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 00 bar" , 7) ... OK: got object of type [string]: "fff 😀 bar" json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue json_tokener_parse_ex(tok, : "bar"} , 8) ... OK: got correct error: unexpected character json_tokener_parse_ex(tok, { "foo , 6) ... OK: got correct error: continue @@ -240,5 +246,5 @@ json_tokener_parse_ex(tok, "\ud855 json_tokener_parse_ex(tok, "\ud0031À" , 10) ... OK: got correct error: invalid utf-8 string json_tokener_parse_ex(tok, 1111 , 5) ... OK: got correct error: invalid utf-8 string json_tokener_parse_ex(tok, {"1":1} , 8) ... OK: got correct error: invalid utf-8 string -End Incremental Tests OK=154 ERROR=0 +End Incremental Tests OK=160 ERROR=0 ================================== From 7d3c2d9fad992293c1001e86789b866a5a168e4d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 21 Jun 2020 18:30:40 +0000 Subject: [PATCH 40/94] Drop extra blank lines from arraylist.h --- arraylist.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arraylist.h b/arraylist.h index 2c0fe93..1b18756 100644 --- a/arraylist.h +++ b/arraylist.h @@ -75,14 +75,12 @@ extern void *array_list_bsearch(const void **key, struct array_list *arr, extern int array_list_del_idx(struct array_list *arr, size_t idx, size_t count); - /** * Shrink the array list to just enough to fit the number of elements in it, * plus empty_slots. */ extern int array_list_shrink(struct array_list *arr, size_t empty_slots); - #ifdef __cplusplus } #endif From 7a72805e344509170c1665522c4f82a96d050ea7 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 22 Jun 2020 01:12:03 +0000 Subject: [PATCH 41/94] Fix memory leak in test_parse's single_incremental_parse(). --- tests/test_parse.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_parse.c b/tests/test_parse.c index da82b51..c2a271c 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -72,6 +72,10 @@ static void single_incremental_parse(const char *test_string, int clear_serializ chunksize, all_at_once_str, new_str); } json_tokener_free(tok); + if (all_at_once_obj) + json_object_put(all_at_once_obj); + if (new_obj) + json_object_put(new_obj); } static void single_basic_parse(const char *test_string, int clear_serializer) From 84e6032883b507f16c877297da97927ea87811f1 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 23 Jun 2020 02:51:46 +0000 Subject: [PATCH 42/94] Issue #635: Fix "expression has no effect" warning in json_tokener.c by casting to void. --- json_tokener.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_tokener.c b/json_tokener.c index 82cb8d9..3855570 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -646,7 +646,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * if (tok->st_pos >= 4) break; - ADVANCE_CHAR(str, tok); + (void)ADVANCE_CHAR(str, tok); if (!PEEK_CHAR(c, tok)) { /* From 6eac6986c9a734b183e55a80e84fa67e58c637ff Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 27 Jun 2020 15:32:19 +0000 Subject: [PATCH 43/94] Fix incremental parsing of invalid numbers with exponents, such as "0e+-" and "12.3E12E12", while still allowing "0e+" in non-strict mode. Deprecate the json_parse_double() function from json_util.h --- ChangeLog | 3 ++ json_tokener.c | 80 ++++++++++++++++++++++++++++++++------- json_util.c | 3 +- json_util.h | 3 ++ tests/test_parse.c | 27 ++++++++++++- tests/test_parse.expected | 21 +++++++++- 6 files changed, 120 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0ca4b59..32c2869 100644 --- a/ChangeLog +++ b/ChangeLog @@ -27,6 +27,9 @@ Other changes arrays to be allocated with the exact size needed, when known. * Parsing of surrogate pairs in unicode escapes now properly handles incremental parsing. +* Fix incremental parsing of numbers, especially those with exponents, e.g. + so parsing "[0", "e+", "-]" now properly returns an error. + Strict mode now rejects missing exponents ("0e"). *** diff --git a/json_tokener.c b/json_tokener.c index 3855570..b949d10 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -97,6 +97,8 @@ static const char *json_tokener_errors[] = { */ static json_bool json_tokener_validate_utf8(const char c, unsigned int *nBytes); +static int json_tokener_parse_double(const char *buf, int len, double *retval); + const char *json_tokener_error_desc(enum json_tokener_error jerr) { int jerr_int = (int)jerr; @@ -837,6 +839,25 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * int case_len = 0; int is_exponent = 0; int negativesign_next_possible_location = 1; + if (printbuf_length(tok->pb) > 0) + { + /* We don't save all state from the previous incremental parse + so we need to re-generate it based on the saved string so far. + */ + char *e_loc = strchr(tok->pb->buf, 'e'); + if (!e_loc) + e_loc = strchr(tok->pb->buf, 'E'); + if (e_loc) + { + char *last_saved_char = + &tok->pb->buf[printbuf_length(tok->pb) - 1]; + is_exponent = 1; + /* If the "e" isn't at the end, we can't start with a '-' */ + if (e_loc != last_saved_char) + negativesign_next_possible_location = -1; + // else leave it set to 1, i.e. start of the new input + } + } while (c && strchr(json_number_chars, c)) { ++case_len; @@ -847,8 +868,9 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * * protected from input starting with '.' or * e/E. */ - if (c == '.') + switch (c) { + case '.': if (tok->is_double != 0) { /* '.' can only be found once, and out of the exponent part. @@ -859,9 +881,9 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * goto out; } tok->is_double = 1; - } - if (c == 'e' || c == 'E') - { + break; + case 'e': /* FALLTHRU */ + case 'E': if (is_exponent != 0) { /* only one exponent possible */ @@ -872,15 +894,19 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * tok->is_double = 1; /* the exponent part can begin with a negative sign */ negativesign_next_possible_location = case_len + 1; - } - if (c == '-' && case_len != negativesign_next_possible_location) - { - /* If the negative sign is not where expected (ie - * start of input or start of exponent part), the - * input is invalid. - */ - tok->err = json_tokener_error_parse_number; - goto out; + break; + case '-': + if (case_len != negativesign_next_possible_location) + { + /* If the negative sign is not where expected (ie + * start of input or start of exponent part), the + * input is invalid. + */ + tok->err = json_tokener_error_parse_number; + goto out; + } + break; + default: break; } if (!ADVANCE_CHAR(str, tok) || !PEEK_CHAR(c, tok)) @@ -899,6 +925,22 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * tok->st_pos = 0; goto redo_char; } + if (tok->is_double && !(tok->flags & JSON_TOKENER_STRICT)) + { + /* Trim some chars off the end, to allow things + like "123e+" to parse ok. */ + while (printbuf_length(tok->pb) > 1) + { + char last_char = tok->pb->buf[printbuf_length(tok->pb) - 1]; + if (last_char != 'e' && last_char != 'E' && + last_char != '-' && last_char != '+') + { + break; + } + tok->pb->buf[printbuf_length(tok->pb) - 1] = '\0'; + printbuf_length(tok->pb)--; + } + } } { int64_t num64; @@ -935,7 +977,8 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * } } else if (tok->is_double && - json_parse_double(tok->pb->buf, &numd) == 0) + json_tokener_parse_double( + tok->pb->buf, printbuf_length(tok->pb), &numd) == 0) { current = json_object_new_double_s(numd, tok->pb->buf); if (current == NULL) @@ -1204,3 +1247,12 @@ size_t json_tokener_get_parse_end(struct json_tokener *tok) assert(tok->char_offset >= 0); /* Drop this line when char_offset becomes a size_t */ return (size_t)tok->char_offset; } + +static int json_tokener_parse_double(const char *buf, int len, double *retval) +{ + char *end; + *retval = strtod(buf, &end); + if (buf + len == end) + return 0; // It worked + return 1; +} diff --git a/json_util.c b/json_util.c index e8e2ec6..a065523 100644 --- a/json_util.c +++ b/json_util.c @@ -222,6 +222,7 @@ int json_object_to_file(const char *filename, struct json_object *obj) return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); } +// Deprecated json_parse_double function. See json_tokener_parse_double instead. int json_parse_double(const char *buf, double *retval) { char *end; @@ -250,7 +251,7 @@ int json_parse_uint64(const char *buf, uint64_t *retval) while (*buf == ' ') buf++; if (*buf == '-') - return 1; /* error: uint cannot be negative */ + return 1; /* error: uint cannot be negative */ val = strtoull(buf, &end, 10); if (end != buf) diff --git a/json_util.h b/json_util.h index 7520f03..1f663e8 100644 --- a/json_util.h +++ b/json_util.h @@ -103,6 +103,9 @@ JSON_EXPORT const char *json_util_get_last_err(void); /* these parsing helpers return zero on success */ JSON_EXPORT int json_parse_int64(const char *buf, int64_t *retval); JSON_EXPORT int json_parse_uint64(const char *buf, uint64_t *retval); +/** + * @deprecated + */ JSON_EXPORT int json_parse_double(const char *buf, double *retval); /** diff --git a/tests/test_parse.c b/tests/test_parse.c index c2a271c..2e17215 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -343,9 +343,34 @@ struct incremental_step /* This should parse as the number 12, since it continues the "1" */ {"2", 2, 1, json_tokener_success, 0}, {"12{", 3, 2, json_tokener_success, 1}, - /* Parse number in strict model */ + /* Parse number in strict mode */ {"[02]", -1, 3, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, + {"0e+0", 5, 4, json_tokener_success, 1}, + {"[0e+0]", -1, -1, json_tokener_success, 1}, + + /* The behavior when missing the exponent varies slightly */ + {"0e", 2, 2, json_tokener_continue, 1}, + {"0e", 3, 2, json_tokener_success, 1}, + {"0e", 3, 2, json_tokener_error_parse_eof, 1, JSON_TOKENER_STRICT}, + {"[0e]", -1, -1, json_tokener_success, 1}, + {"[0e]", -1, 3, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, + + {"0e+", 3, 3, json_tokener_continue, 1}, + {"0e+", 4, 3, json_tokener_success, 1}, + {"0e+", 4, 3, json_tokener_error_parse_eof, 1, JSON_TOKENER_STRICT}, + {"[0e+]", -1, -1, json_tokener_success, 1}, + {"[0e+]", -1, 4, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, + + {"0e-", 3, 3, json_tokener_continue, 1}, + {"0e-", 4, 3, json_tokener_success, 1}, + {"0e-", 4, 3, json_tokener_error_parse_eof, 1, JSON_TOKENER_STRICT}, + {"[0e-]", -1, -1, json_tokener_success, 1}, + {"[0e-]", -1, 4, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, + + {"0e+-", 5, 3, json_tokener_error_parse_number, 1}, + {"[0e+-]", -1, 4, json_tokener_error_parse_number, 1}, + /* Similar tests for other kinds of objects: */ /* These could all return success immediately, since regardless of what follows the false/true/null token we *will* return a json object, diff --git a/tests/test_parse.expected b/tests/test_parse.expected index 6ed5520..48539fc 100644 --- a/tests/test_parse.expected +++ b/tests/test_parse.expected @@ -145,6 +145,25 @@ json_tokener_parse_ex(tok, 1 , 1) ... OK: got correct error: continu json_tokener_parse_ex(tok, 2 , 2) ... OK: got object of type [int]: 12 json_tokener_parse_ex(tok, 12{ , 3) ... OK: got object of type [int]: 12 json_tokener_parse_ex(tok, [02] , 4) ... OK: got correct error: number expected +json_tokener_parse_ex(tok, 0e+0 , 5) ... OK: got object of type [double]: 0e+0 +json_tokener_parse_ex(tok, [0e+0] , 6) ... OK: got object of type [array]: [ 0e+0 ] +json_tokener_parse_ex(tok, 0e , 2) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 0e , 3) ... OK: got object of type [double]: 0 +json_tokener_parse_ex(tok, 0e , 3) ... OK: got correct error: unexpected end of data +json_tokener_parse_ex(tok, [0e] , 4) ... OK: got object of type [array]: [ 0 ] +json_tokener_parse_ex(tok, [0e] , 4) ... OK: got correct error: number expected +json_tokener_parse_ex(tok, 0e+ , 3) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 0e+ , 4) ... OK: got object of type [double]: 0 +json_tokener_parse_ex(tok, 0e+ , 4) ... OK: got correct error: unexpected end of data +json_tokener_parse_ex(tok, [0e+] , 5) ... OK: got object of type [array]: [ 0 ] +json_tokener_parse_ex(tok, [0e+] , 5) ... OK: got correct error: number expected +json_tokener_parse_ex(tok, 0e- , 3) ... OK: got correct error: continue +json_tokener_parse_ex(tok, 0e- , 4) ... OK: got object of type [double]: 0 +json_tokener_parse_ex(tok, 0e- , 4) ... OK: got correct error: unexpected end of data +json_tokener_parse_ex(tok, [0e-] , 5) ... OK: got object of type [array]: [ 0 ] +json_tokener_parse_ex(tok, [0e-] , 5) ... OK: got correct error: number expected +json_tokener_parse_ex(tok, 0e+- , 5) ... OK: got correct error: number expected +json_tokener_parse_ex(tok, [0e+-] , 6) ... OK: got correct error: number expected json_tokener_parse_ex(tok, false , 5) ... OK: got correct error: continue json_tokener_parse_ex(tok, false , 6) ... OK: got object of type [boolean]: false json_tokener_parse_ex(tok, true , 4) ... OK: got correct error: continue @@ -246,5 +265,5 @@ json_tokener_parse_ex(tok, "\ud855 json_tokener_parse_ex(tok, "\ud0031À" , 10) ... OK: got correct error: invalid utf-8 string json_tokener_parse_ex(tok, 1111 , 5) ... OK: got correct error: invalid utf-8 string json_tokener_parse_ex(tok, {"1":1} , 8) ... OK: got correct error: invalid utf-8 string -End Incremental Tests OK=160 ERROR=0 +End Incremental Tests OK=179 ERROR=0 ================================== From f23486a3217ed85ed4a0d7f95a10c4013250c987 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 29 Jun 2020 02:14:26 +0000 Subject: [PATCH 44/94] In the json_tokener_state_number case, explicitly adjust what "number" characters are allowed based on the exact micro-state that we're in, and check for invalid following characters in a different way, to allow a valid json_type_number object to be returned at the top level. This causes previously failing strings like "123-456" to return a valid json_object with the appropriate value. If you care about the trailing content, call json_tokener_parse_ex() and check the parse end point with json_tokener_get_parse_end(). --- ChangeLog | 3 ++ json_object.c | 1 - json_object_private.h | 1 - json_tokener.c | 77 +++++++++++++++++++++++---------------- tests/test_parse.c | 42 ++++++++++++++------- tests/test_parse.expected | 18 +++++++-- 6 files changed, 92 insertions(+), 50 deletions(-) diff --git a/ChangeLog b/ChangeLog index 32c2869..6e46cda 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,9 @@ Other changes * Fix incremental parsing of numbers, especially those with exponents, e.g. so parsing "[0", "e+", "-]" now properly returns an error. Strict mode now rejects missing exponents ("0e"). +* Successfully return number objects at the top level even when they are + followed by a "-", "." or "e". This makes parsing things like "123-45" + behave consistently with things like "123xyz". *** diff --git a/json_object.c b/json_object.c index 89439ab..1dffd00 100644 --- a/json_object.c +++ b/json_object.c @@ -54,7 +54,6 @@ // Don't define this. It's not thread-safe. /* #define REFCOUNT_DEBUG 1 */ -const char *json_number_chars = "0123456789.+-eE"; const char *json_hex_chars = "0123456789abcdefABCDEF"; static void json_object_generic_delete(struct json_object *jso); diff --git a/json_object_private.h b/json_object_private.h index d1d782e..e143b46 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -98,7 +98,6 @@ struct json_object_string void _json_c_set_last_err(const char *err_fmt, ...); -extern const char *json_number_chars; extern const char *json_hex_chars; #ifdef __cplusplus diff --git a/json_tokener.c b/json_tokener.c index b949d10..0d01d2b 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -193,7 +193,17 @@ struct json_object *json_tokener_parse_verbose(const char *str, enum json_tokene return NULL; obj = json_tokener_parse_ex(tok, str, -1); *error = tok->err; - if (tok->err != json_tokener_success) + if (tok->err != json_tokener_success +#if 0 + /* This would be a more sensible default, and cause parsing + * things like "null123" to fail when the caller can't know + * where the parsing left off, but starting to fail would + * be a notable behaviour change. Save for a 1.0 release. + */ + || json_tokener_get_parse_end(tok) != strlen(str) +#endif + ) + { if (obj != NULL) json_object_put(obj); @@ -838,7 +848,8 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * const char *case_start = str; int case_len = 0; int is_exponent = 0; - int negativesign_next_possible_location = 1; + int neg_sign_ok = 1; + int pos_sign_ok = 0; if (printbuf_length(tok->pb) > 0) { /* We don't save all state from the previous incremental parse @@ -852,14 +863,26 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * char *last_saved_char = &tok->pb->buf[printbuf_length(tok->pb) - 1]; is_exponent = 1; + pos_sign_ok = neg_sign_ok = 1; /* If the "e" isn't at the end, we can't start with a '-' */ if (e_loc != last_saved_char) - negativesign_next_possible_location = -1; + { + neg_sign_ok = 0; + pos_sign_ok = 0; + } // else leave it set to 1, i.e. start of the new input } } - while (c && strchr(json_number_chars, c)) + + while (c && + ((c >= '0' && c <= '9') || + (!is_exponent && (c=='e' || c=='E')) || + (neg_sign_ok && c=='-') || + (pos_sign_ok && c=='+') || + (!tok->is_double && c=='.') + )) { + pos_sign_ok = neg_sign_ok = 0; ++case_len; /* non-digit characters checks */ @@ -871,40 +894,16 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * switch (c) { case '.': - if (tok->is_double != 0) - { - /* '.' can only be found once, and out of the exponent part. - * Thus, if the input is already flagged as double, it - * is invalid. - */ - tok->err = json_tokener_error_parse_number; - goto out; - } tok->is_double = 1; + pos_sign_ok = 1; + neg_sign_ok = 1; break; case 'e': /* FALLTHRU */ case 'E': - if (is_exponent != 0) - { - /* only one exponent possible */ - tok->err = json_tokener_error_parse_number; - goto out; - } is_exponent = 1; tok->is_double = 1; /* the exponent part can begin with a negative sign */ - negativesign_next_possible_location = case_len + 1; - break; - case '-': - if (case_len != negativesign_next_possible_location) - { - /* If the negative sign is not where expected (ie - * start of input or start of exponent part), the - * input is invalid. - */ - tok->err = json_tokener_error_parse_number; - goto out; - } + pos_sign_ok = neg_sign_ok = 1; break; default: break; } @@ -915,6 +914,22 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * goto out; } } + /* + Now we know c isn't a valid number char, but check whether + it might have been intended to be, and return a potentially + more understandable error right away. + However, if we're at the top-level, use the number as-is + because c can be part of a new object to parse on the + next call to json_tokener_parse(). + */ + if (tok->depth > 0 && + c != ',' && c != ']' && c != '}' && c != '/' && + c != 'I' && c != 'i' && + !isspace((unsigned char)c)) + { + tok->err = json_tokener_error_parse_number; + goto out; + } if (case_len > 0) printbuf_memappend_fast(tok->pb, case_start, case_len); diff --git a/tests/test_parse.c b/tests/test_parse.c index 2e17215..3c9ac82 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -141,16 +141,18 @@ static void test_basic_parse() single_basic_parse("12", 0); single_basic_parse("12.3", 0); - single_basic_parse("12.3.4", 0); /* non-sensical, returns null */ - /* was returning (int)2015 before patch, should return null */ - single_basic_parse("2015-01-15", 0); - /* ...but this works. It's rather inconsistent, and a future major release - * should change the behavior so it either always returns null when extra - * bytes are present (preferred), or always return object created from as much - * as was able to be parsed. + /* Even though, when using json_tokener_parse() there's no way to + * know when there is more data after the parsed object, + * an object is successfully returned anyway (in some cases) */ + + single_basic_parse("12.3.4", 0); + single_basic_parse("2015-01-15", 0); single_basic_parse("12.3xxx", 0); + single_basic_parse("12.3{\"a\":123}", 0); + single_basic_parse("12.3\n", 0); + single_basic_parse("12.3 ", 0); single_basic_parse("{\"FoO\" : -12.3E512}", 0); single_basic_parse("{\"FoO\" : -12.3e512}", 0); @@ -368,7 +370,10 @@ struct incremental_step {"[0e-]", -1, -1, json_tokener_success, 1}, {"[0e-]", -1, 4, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, - {"0e+-", 5, 3, json_tokener_error_parse_number, 1}, + /* You might expect this to fail, but it won't because + it's a valid partial parse; note the char_offset: */ + {"0e+-", 5, 3, json_tokener_success, 1}, + {"0e+-", 5, 3, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, {"[0e+-]", -1, 4, json_tokener_error_parse_number, 1}, /* Similar tests for other kinds of objects: */ @@ -447,11 +452,22 @@ struct incremental_step {"{\"a\":1}{\"b\":2}", 15, 7, json_tokener_success, 0}, {&"{\"a\":1}{\"b\":2}"[7], 8, 7, json_tokener_success, 1}, - /* Some bad formatting. Check we get the correct error status - * XXX this means we can't have two numbers in the incremental parse - * XXX stream with the second one being a negative number! - */ - {"2015-01-15", 10, 4, json_tokener_error_parse_number, 1}, + /* + * Though this may seem invalid at first glance, it + * parses as three separate numbers, 2015, -1 and -15 + * Of course, simply pasting together a stream of arbitrary + * positive numbers won't work, since there'll be no way to + * tell where in e.g. "2015015" the next number stats, so + * a reliably parsable stream must not include json_type_int + * or json_type_double objects without some other delimiter. + * e.g. whitespace + */ + {&"2015-01-15"[0], 11, 4, json_tokener_success, 1}, + {&"2015-01-15"[4], 7, 3, json_tokener_success, 1}, + {&"2015-01-15"[7], 4, 3, json_tokener_success, 1}, + {&"2015 01 15"[0], 11, 5, json_tokener_success, 1}, + {&"2015 01 15"[4], 7, 4, json_tokener_success, 1}, + {&"2015 01 15"[7], 4, 3, json_tokener_success, 1}, /* Strings have a well defined end point, so we can stop at the quote */ {"\"blue\"", -1, -1, json_tokener_success, 0}, diff --git a/tests/test_parse.expected b/tests/test_parse.expected index 48539fc..37db44d 100644 --- a/tests/test_parse.expected +++ b/tests/test_parse.expected @@ -40,9 +40,13 @@ new_obj.to_string(nAn)=NaN new_obj.to_string(iNfinity)=Infinity new_obj.to_string(12)=12 new_obj.to_string(12.3)=12.3 -new_obj.to_string(12.3.4)=null -new_obj.to_string(2015-01-15)=null +new_obj.to_string(12.3.4)=12.3 +new_obj.to_string(2015-01-15)=2015 new_obj.to_string(12.3xxx)=12.3 +new_obj.to_string(12.3{"a":123})=12.3 +new_obj.to_string(12.3 +)=12.3 +new_obj.to_string(12.3 )=12.3 new_obj.to_string({"FoO" : -12.3E512})={ "FoO": -12.3E512 } new_obj.to_string({"FoO" : -12.3e512})={ "FoO": -12.3e512 } new_obj.to_string({"FoO" : -12.3E51.2})=null @@ -162,6 +166,7 @@ json_tokener_parse_ex(tok, 0e- , 4) ... OK: got object of type [double json_tokener_parse_ex(tok, 0e- , 4) ... OK: got correct error: unexpected end of data json_tokener_parse_ex(tok, [0e-] , 5) ... OK: got object of type [array]: [ 0 ] json_tokener_parse_ex(tok, [0e-] , 5) ... OK: got correct error: number expected +json_tokener_parse_ex(tok, 0e+- , 5) ... OK: got object of type [double]: 0 json_tokener_parse_ex(tok, 0e+- , 5) ... OK: got correct error: number expected json_tokener_parse_ex(tok, [0e+-] , 6) ... OK: got correct error: number expected json_tokener_parse_ex(tok, false , 5) ... OK: got correct error: continue @@ -215,7 +220,12 @@ json_tokener_parse_ex(tok, nullx , 6) ... OK: got object of type [null]: json_tokener_parse_ex(tok, x , 2) ... OK: got correct error: unexpected character json_tokener_parse_ex(tok, {"a":1}{"b":2}, 15) ... OK: got object of type [object]: { "a": 1 } json_tokener_parse_ex(tok, {"b":2} , 8) ... OK: got object of type [object]: { "b": 2 } -json_tokener_parse_ex(tok, 2015-01-15 , 10) ... OK: got correct error: number expected +json_tokener_parse_ex(tok, 2015-01-15 , 11) ... OK: got object of type [int]: 2015 +json_tokener_parse_ex(tok, -01-15 , 7) ... OK: got object of type [int]: -1 +json_tokener_parse_ex(tok, -15 , 4) ... OK: got object of type [int]: -15 +json_tokener_parse_ex(tok, 2015 01 15 , 11) ... OK: got object of type [int]: 2015 +json_tokener_parse_ex(tok, 01 15 , 7) ... OK: got object of type [int]: 1 +json_tokener_parse_ex(tok, 15 , 4) ... OK: got object of type [int]: 15 json_tokener_parse_ex(tok, "blue" , 6) ... OK: got object of type [string]: "blue" json_tokener_parse_ex(tok, "\"" , 4) ... OK: got object of type [string]: "\"" json_tokener_parse_ex(tok, "\\" , 4) ... OK: got object of type [string]: "\\" @@ -265,5 +275,5 @@ json_tokener_parse_ex(tok, "\ud855 json_tokener_parse_ex(tok, "\ud0031À" , 10) ... OK: got correct error: invalid utf-8 string json_tokener_parse_ex(tok, 1111 , 5) ... OK: got correct error: invalid utf-8 string json_tokener_parse_ex(tok, {"1":1} , 8) ... OK: got correct error: invalid utf-8 string -End Incremental Tests OK=179 ERROR=0 +End Incremental Tests OK=185 ERROR=0 ================================== From 5f3bf70f039920d31a43a21f36a2ac02df41b7cd Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 29 Jun 2020 02:18:34 +0000 Subject: [PATCH 45/94] Make sure TEST_PARSE_CHUNKSIZE is valid if it's set. --- tests/test_parse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_parse.c b/tests/test_parse.c index 3c9ac82..d84b9d6 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -42,6 +42,7 @@ static void single_incremental_parse(const char *test_string, int clear_serializ json_object *all_at_once_obj, *new_obj; const char *all_at_once_str, *new_str; + assert(chunksize > 0); all_at_once_obj = json_tokener_parse(test_string); if (clear_serializer) do_clear_serializer(all_at_once_obj); From a4e3700972fe1582189d7b5594b54b940894bdff Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 29 Jun 2020 02:31:18 +0000 Subject: [PATCH 46/94] Fix code formatting --- json_tokener.c | 19 +++++++------------ tests/test_parse.c | 4 ++-- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/json_tokener.c b/json_tokener.c index 0d01d2b..63e02a1 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -202,7 +202,7 @@ struct json_object *json_tokener_parse_verbose(const char *str, enum json_tokene */ || json_tokener_get_parse_end(tok) != strlen(str) #endif - ) + ) { if (obj != NULL) @@ -874,13 +874,10 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * } } - while (c && - ((c >= '0' && c <= '9') || - (!is_exponent && (c=='e' || c=='E')) || - (neg_sign_ok && c=='-') || - (pos_sign_ok && c=='+') || - (!tok->is_double && c=='.') - )) + while (c && ((c >= '0' && c <= '9') || + (!is_exponent && (c == 'e' || c == 'E')) || + (neg_sign_ok && c == '-') || (pos_sign_ok && c == '+') || + (!tok->is_double && c == '.'))) { pos_sign_ok = neg_sign_ok = 0; ++case_len; @@ -922,10 +919,8 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * because c can be part of a new object to parse on the next call to json_tokener_parse(). */ - if (tok->depth > 0 && - c != ',' && c != ']' && c != '}' && c != '/' && - c != 'I' && c != 'i' && - !isspace((unsigned char)c)) + if (tok->depth > 0 && c != ',' && c != ']' && c != '}' && c != '/' && + c != 'I' && c != 'i' && !isspace((unsigned char)c)) { tok->err = json_tokener_error_parse_number; goto out; diff --git a/tests/test_parse.c b/tests/test_parse.c index d84b9d6..5363f32 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -371,7 +371,7 @@ struct incremental_step {"[0e-]", -1, -1, json_tokener_success, 1}, {"[0e-]", -1, 4, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, - /* You might expect this to fail, but it won't because + /* You might expect this to fail, but it won't because it's a valid partial parse; note the char_offset: */ {"0e+-", 5, 3, json_tokener_success, 1}, {"0e+-", 5, 3, json_tokener_error_parse_number, 1, JSON_TOKENER_STRICT}, @@ -453,7 +453,7 @@ struct incremental_step {"{\"a\":1}{\"b\":2}", 15, 7, json_tokener_success, 0}, {&"{\"a\":1}{\"b\":2}"[7], 8, 7, json_tokener_success, 1}, - /* + /* * Though this may seem invalid at first glance, it * parses as three separate numbers, 2015, -1 and -15 * Of course, simply pasting together a stream of arbitrary From 0b67caec1a72c1e89d8a34f9094ad40ac6d9faf9 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 29 Jun 2020 02:31:32 +0000 Subject: [PATCH 47/94] Add doc comment for json_object_new_array_ext(). --- json_object.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/json_object.h b/json_object.h index 5f2f64c..d331818 100644 --- a/json_object.h +++ b/json_object.h @@ -500,6 +500,7 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key /* Array type methods */ /** Create a new empty json_object of type json_type_array + * with 32 slots allocated. * If you know the array size you'll need ahead of time, use * json_object_new_array_ext() instead. * @see json_object_new_array_ext() @@ -508,6 +509,12 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key */ JSON_EXPORT struct json_object *json_object_new_array(void); +/** Create a new empty json_object of type json_type_array + * with the desired number of slots allocated. + * @see json_object_array_shrink() + * @param initial_size the number of slots to allocate + * @returns a json_object of type json_type_array + */ JSON_EXPORT struct json_object *json_object_new_array_ext(int initial_size); /** Get the arraylist of a json_object of type json_type_array From 34334e5d3f89fe7c1e07e776761f5fa614e67fb7 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 29 Jun 2020 02:35:26 +0000 Subject: [PATCH 48/94] Replace one call to json_object_new_array() with json_object_new_array_ext() to ensure it at least minimally works. --- tests/test1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test1.c b/tests/test1.c index 98546bf..6682120 100644 --- a/tests/test1.c +++ b/tests/test1.c @@ -250,7 +250,7 @@ int main(int argc, char **argv) test_array_del_idx(); test_array_list_expand_internal(); - my_array = json_object_new_array(); + my_array = json_object_new_array_ext(5); json_object_array_add(my_array, json_object_new_int(3)); json_object_array_add(my_array, json_object_new_int(1)); json_object_array_add(my_array, json_object_new_int(2)); From 6465e74020fd5418043a4b23ffdc2011e34f0c7a Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Wed, 1 Jul 2020 00:34:46 +0000 Subject: [PATCH 49/94] Use constants referring to the signed integer types when setting SSIZE_T_MAX. In practice, the sizes of the signed and unsigned integer types will almost cetainly be the same, but this is more correct. Pointed out in issue #638. --- json_object.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/json_object.c b/json_object.c index 1dffd00..73daa4c 100644 --- a/json_object.c +++ b/json_object.c @@ -41,11 +41,11 @@ #ifndef SSIZE_T_MAX #if SIZEOF_SSIZE_T == SIZEOF_INT -#define SSIZE_T_MAX UINT_MAX +#define SSIZE_T_MAX INT_MAX #elif SIZEOF_SSIZE_T == SIZEOF_LONG -#define SSIZE_T_MAX ULONG_MAX +#define SSIZE_T_MAX LONG_MAX #elif SIZEOF_SSIZE_T == SIZEOF_LONG_LONG -#define SSIZE_T_MAX ULLONG_MAX +#define SSIZE_T_MAX LLONG_MAX #else #error Unable to determine size of ssize_t #endif From c2c94024f5d15c2fe36c72cb139df6a2ccd9b3ec Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 29 Jun 2020 18:16:34 +0100 Subject: [PATCH 50/94] build: Add symbol versions to all exported symbols With this version script, newly-linked binaries that depend on the json-c shared library will refer to its symbols in a versioned form, preventing their references from being resolved to a symbol of the same name exported by json-glib or libjansson if those libraries appear in dependency search order before json-c, which will usually result in a crash. This is necessary because ELF symbol resolution normally uses a single flat namespace, not a tree like Windows symbol resolution. At least one symbol (json_object_iter_next()) is exported by all three JSON libraries. Linking with -Bsymbolic is not enough to have this effect in all cases, because -Bsymbolic only affects symbol lookup within a shared object, for example when json_object_set_serializer() calls json_object_set_userdata(). It does not affect calls from external code into json-c, unless json-c was statically linked into the external caller. This change will also not prevent code that depends on json-glib or libjansson from finding json-c's symbols and crashing; to prevent that, a corresponding change in json-glib or libjansson would be needed. Adding a symbol-version is a backwards-compatible change, but once added, removing or changing the symbol-version on a symbol would be an incompatible change that requires a SONAME bump. Resolves: https://github.com/json-c/json-c/issues/621 (when combined with an equivalent change to libjansson). Signed-off-by: Simon McVittie --- CMakeLists.txt | 16 ++++++ json-c.sym | 153 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 json-c.sym diff --git a/CMakeLists.txt b/CMakeLists.txt index 21e395e..da0af96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -325,6 +325,22 @@ if (NOT ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")) # XXX need cmake>=3.13 for this: #add_link_options("-Wl,-Bsymbolic-functions") endif() + + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/check-version-script.sym" "TEST { global: *; };") + list(APPEND CMAKE_REQUIRED_LIBRARIES "-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/check-version-script.sym") + check_c_source_compiles( + " + int main (void) + { + return 0; + } + " + VERSION_SCRIPT_WORKS + ) + list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/check-version-script.sym") + if (VERSION_SCRIPT_WORKS) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--version-script,${CMAKE_CURRENT_SOURCE_DIR}/json-c.sym") + endif() endif() if ($ENV{VALGRIND}) diff --git a/json-c.sym b/json-c.sym new file mode 100644 index 0000000..bf78792 --- /dev/null +++ b/json-c.sym @@ -0,0 +1,153 @@ +JSONC_0.14 { + global: + _json_c_set_last_err; + _json_c_strerror; + _json_c_strerror_enable; + array_list_add; + array_list_bsearch; + array_list_del_idx; + array_list_free; + array_list_get_idx; + array_list_length; + array_list_new; + array_list_put_idx; + array_list_sort; + json_c_get_random_seed; + json_c_object_sizeof; + json_c_set_serialization_double_format; + json_c_shallow_copy_default; + json_c_version; + json_c_version_num; + json_c_visit; + json_global_set_string_hash; + json_hex_chars; + json_number_chars; + json_object_array_add; + json_object_array_bsearch; + json_object_array_del_idx; + json_object_array_get_idx; + json_object_array_length; + json_object_array_put_idx; + json_object_array_sort; + json_object_deep_copy; + json_object_double_to_json_string; + json_object_equal; + json_object_free_userdata; + json_object_from_fd; + json_object_from_fd_ex; + json_object_from_file; + json_object_get; + json_object_get_array; + json_object_get_boolean; + json_object_get_double; + json_object_get_int64; + json_object_get_int; + json_object_get_object; + json_object_get_string; + json_object_get_string_len; + json_object_get_type; + json_object_get_uint64; + json_object_get_userdata; + json_object_int_inc; + json_object_is_type; + json_object_iter_begin; + json_object_iter_end; + json_object_iter_equal; + json_object_iter_init_default; + json_object_iter_next; + json_object_iter_peek_name; + json_object_iter_peek_value; + json_object_new_array; + json_object_new_boolean; + json_object_new_double; + json_object_new_double_s; + json_object_new_int64; + json_object_new_int; + json_object_new_null; + json_object_new_object; + json_object_new_string; + json_object_new_string_len; + json_object_new_uint64; + json_object_object_add; + json_object_object_add_ex; + json_object_object_del; + json_object_object_get; + json_object_object_get_ex; + json_object_object_length; + json_object_put; + json_object_set_boolean; + json_object_set_double; + json_object_set_int64; + json_object_set_int; + json_object_set_serializer; + json_object_set_string; + json_object_set_string_len; + json_object_set_uint64; + json_object_set_userdata; + json_object_to_fd; + json_object_to_file; + json_object_to_file_ext; + json_object_to_json_string; + json_object_to_json_string_ext; + json_object_to_json_string_length; + json_object_userdata_to_json_string; + json_parse_double; + json_parse_int64; + json_parse_uint64; + json_pointer_get; + json_pointer_getf; + json_pointer_set; + json_pointer_setf; + json_tokener_error_desc; + json_tokener_free; + json_tokener_get_error; + json_tokener_get_parse_end; + json_tokener_new; + json_tokener_new_ex; + json_tokener_parse; + json_tokener_parse_ex; + json_tokener_parse_verbose; + json_tokener_reset; + json_tokener_set_flags; + json_type_to_name; + json_util_get_last_err; + lh_char_equal; + lh_kchar_table_new; + lh_kptr_table_new; + lh_ptr_equal; + lh_table_delete; + lh_table_delete_entry; + lh_table_free; + lh_table_insert; + lh_table_insert_w_hash; + lh_table_length; + lh_table_lookup; + lh_table_lookup_entry; + lh_table_lookup_entry_w_hash; + lh_table_lookup_ex; + lh_table_new; + lh_table_resize; + mc_debug; + mc_error; + mc_get_debug; + mc_info; + mc_set_debug; + mc_set_syslog; + printbuf_free; + printbuf_memappend; + printbuf_memset; + printbuf_new; + printbuf_reset; + sprintbuf; + + local: + *; +}; + +JSONC_0.15 { + global: + array_list_new2; + array_list_shrink; + json_object_array_shrink; + json_object_new_array_ext; +} JSONC_0.14; From 6068d3f6d1dd4bd8be95e6bf4ed3e9148291b408 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 4 Jul 2020 18:56:15 +0000 Subject: [PATCH 51/94] Change the strerror_override handling to check $_JSON_C_STRERROR_OVERRIDE instead of using a variable, so we don't need to export it. --- strerror_override.c | 5 ++++- tests/CMakeLists.txt | 4 ++++ tests/test_basic.test | 2 ++ tests/test_json_pointer.c | 5 +---- tests/test_util_file.c | 2 -- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/strerror_override.c b/strerror_override.c index a93be38..7a262f7 100644 --- a/strerror_override.c +++ b/strerror_override.c @@ -59,7 +59,8 @@ static struct /* clang-format on */ // Enabled during tests -int _json_c_strerror_enable = 0; +static int _json_c_strerror_enable = 0; +extern char *getenv(const char *name); // Avoid including stdlib.h #define PREFIX "ERRNO=" static char errno_buf[128] = PREFIX; @@ -70,6 +71,8 @@ char *_json_c_strerror(int errno_in) int ii, jj; if (!_json_c_strerror_enable) + _json_c_strerror_enable = (getenv("_JSON_C_STRERROR_ENABLE") == NULL) ? -1 : 1; + if (_json_c_strerror_enable == -1) return strerror(errno_in); // Avoid standard functions, so we don't need to include any diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a871573..125f615 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -37,6 +37,10 @@ foreach(TESTNAME test_object_iterator) add_executable(${TESTNAME} ${TESTNAME}.c) +if(${TESTNAME} STREQUAL test_util_file) +# For output consistency, we need _json_c_strerror() in some tests: +target_sources(${TESTNAME} PRIVATE ../strerror_override.c) +endif() add_test(NAME ${TESTNAME} COMMAND ${PROJECT_SOURCE_DIR}/tests/${TESTNAME}.test) # XXX using the non-target_ versions of these doesn't work :( diff --git a/tests/test_basic.test b/tests/test_basic.test index 154e036..474e7a8 100755 --- a/tests/test_basic.test +++ b/tests/test_basic.test @@ -1,5 +1,7 @@ #!/bin/sh +export _JSON_C_STRERROR_ENABLE=1 + # Common definitions if test -z "$srcdir"; then srcdir="${0%/*}" diff --git a/tests/test_json_pointer.c b/tests/test_json_pointer.c index 34fa202..3174c87 100644 --- a/tests/test_json_pointer.c +++ b/tests/test_json_pointer.c @@ -1,9 +1,8 @@ -#include "strerror_override.h" -#include "strerror_override_private.h" #ifdef NDEBUG #undef NDEBUG #endif #include +#include #include #include @@ -320,8 +319,6 @@ static void test_wrong_inputs_set(void) int main(int argc, char **argv) { - _json_c_strerror_enable = 1; - test_example_get(); test_recursion_get(); test_wrong_inputs_get(); diff --git a/tests/test_util_file.c b/tests/test_util_file.c index 9d50663..9150586 100644 --- a/tests/test_util_file.c +++ b/tests/test_util_file.c @@ -127,8 +127,6 @@ int main(int argc, char **argv) // json_object_to_file(file, obj); // json_object_to_file_ext(file, obj, flags); - _json_c_strerror_enable = 1; - const char *testdir; if (argc < 2) { From 6fa8b7ff4205b9f88d71eb63a3629eb7bf2f4f86 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 4 Jul 2020 18:58:56 +0000 Subject: [PATCH 52/94] Don't export json-c symbols starting with an underscore, put deprecated exports into a "JSONC_PRIVATE" version, and note stuff to do during releases. See also PR #639 and issue #621 --- RELEASE_CHECKLIST.txt | 7 ++++ json-c.sym | 76 +++++++++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index 9ad708c..20c08fd 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -18,6 +18,8 @@ * https://github.com/lvc/abi-compliance-checker * If the new release is not backwards compatible, then this is a MAJOR release. * Mention removed features in ChangeLog + * Consider re-adding backwards compatible support, through symbol + aliases and appropriate entries in json-c.sym * Update the AUTHORS file * Exclude mentioning changes that have already been included in a point release of the previous release branch. @@ -63,6 +65,11 @@ to git commit -a -m "Bump version to ${release}" +If we're doing a major release (SONAME bump), also bump the version + of ALL symbols in json-c.sym. + See explanation at https://github.com/json-c/json-c/issues/621 + More info at: https://software.intel.com/sites/default/files/m/a/1/e/dsohowto.pdf + ------------ Generate the doxygen documentation: diff --git a/json-c.sym b/json-c.sym index bf78792..a348204 100644 --- a/json-c.sym +++ b/json-c.sym @@ -1,17 +1,53 @@ -JSONC_0.14 { - global: - _json_c_set_last_err; - _json_c_strerror; - _json_c_strerror_enable; + +/* + * Symbol versioning for libjson-c. + * All exported symbols must be listed here. + * + * See + * https://software.intel.com/sites/default/files/m/a/1/e/dsohowto.pdf + */ + +/* + * Symbols in JSONC_PRIVATE are exported for historical + * reasons, but should not be used outside of json-c. + */ +JSONC_PRIVATE { array_list_add; - array_list_bsearch; array_list_del_idx; array_list_free; - array_list_get_idx; - array_list_length; array_list_new; array_list_put_idx; array_list_sort; + json_hex_chars; + json_parse_double; + json_parse_int64; + json_parse_uint64; + lh_table_delete; + lh_table_delete_entry; + lh_table_free; + lh_table_insert; + lh_table_insert_w_hash; + lh_table_new; + lh_table_resize; + mc_debug; + mc_error; + mc_get_debug; + mc_info; + mc_set_debug; + mc_set_syslog; + printbuf_free; + printbuf_memappend; + printbuf_memset; + printbuf_new; + printbuf_reset; + sprintbuf; +}; + +JSONC_0.14 { + global: + array_list_bsearch; + array_list_get_idx; + array_list_length; json_c_get_random_seed; json_c_object_sizeof; json_c_set_serialization_double_format; @@ -20,7 +56,6 @@ JSONC_0.14 { json_c_version_num; json_c_visit; json_global_set_string_hash; - json_hex_chars; json_number_chars; json_object_array_add; json_object_array_bsearch; @@ -91,9 +126,6 @@ JSONC_0.14 { json_object_to_json_string_ext; json_object_to_json_string_length; json_object_userdata_to_json_string; - json_parse_double; - json_parse_int64; - json_parse_uint64; json_pointer_get; json_pointer_getf; json_pointer_set; @@ -115,30 +147,10 @@ JSONC_0.14 { lh_kchar_table_new; lh_kptr_table_new; lh_ptr_equal; - lh_table_delete; - lh_table_delete_entry; - lh_table_free; - lh_table_insert; - lh_table_insert_w_hash; lh_table_length; - lh_table_lookup; lh_table_lookup_entry; lh_table_lookup_entry_w_hash; lh_table_lookup_ex; - lh_table_new; - lh_table_resize; - mc_debug; - mc_error; - mc_get_debug; - mc_info; - mc_set_debug; - mc_set_syslog; - printbuf_free; - printbuf_memappend; - printbuf_memset; - printbuf_new; - printbuf_reset; - sprintbuf; local: *; From 10a9ac245eced1dd5b7b20d88e1bf0483dfcd379 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 11 Jul 2020 04:04:58 +0000 Subject: [PATCH 53/94] Issue #642: improve docs for json_tokener.h and json_object_object_add(). --- json_object.h | 24 +++++++++++++++--------- json_tokener.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/json_object.h b/json_object.h index d331818..909c436 100644 --- a/json_object.h +++ b/json_object.h @@ -347,15 +347,21 @@ JSON_C_CONST_FUNCTION(JSON_EXPORT size_t json_c_object_sizeof(void)); /** Add an object field to a json_object of type json_type_object * - * The reference count will *not* be incremented. This is to make adding - * fields to objects in code more compact. If you want to retain a reference - * to an added object, independent of the lifetime of obj, you must wrap the - * passed object with json_object_get. + * The reference count of `val` will *not* be incremented, in effect + * transferring ownership that object to `obj`, and thus `val` will be + * freed when `obj` is. (i.e. through `json_object_put(obj)`) * - * Upon calling this, the ownership of val transfers to obj. Thus you must - * make sure that you do in fact have ownership over this object. For instance, - * json_object_new_object will give you ownership until you transfer it, - * whereas json_object_object_get does not. + * If you want to retain a reference to the added object, independent + * of the lifetime of obj, you must increment the refcount with + * `json_object_get(val)` (and later release it with json_object_put()). + * + * Since ownership transfers to `obj`, you must make sure + * that you do in fact have ownership over `val`. For instance, + * json_object_new_object() will give you ownership until you transfer it, + * whereas json_object_object_get() does not. + * + * Any previous object stored under `key` in `obj` will have its refcount + * decremented, and be freed normally if that drops to zero. * * @param obj the json_object instance * @param key the object field name (a private copy will be duplicated) @@ -378,7 +384,7 @@ JSON_EXPORT int json_object_object_add(struct json_object *obj, const char *key, * @param key the object field name (a private copy will be duplicated) * @param val a json_object or NULL member to associate with the given field * @param opts process-modifying options. To specify multiple options, use - * arithmetic or (OPT1|OPT2) + * (OPT1|OPT2) */ JSON_EXPORT int json_object_object_add_ex(struct json_object *obj, const char *const key, struct json_object *const val, const unsigned opts); diff --git a/json_tokener.h b/json_tokener.h index c680603..a07e12c 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -196,11 +196,44 @@ JSON_EXPORT const char *json_tokener_error_desc(enum json_tokener_error jerr); */ JSON_EXPORT enum json_tokener_error json_tokener_get_error(struct json_tokener *tok); +/** + * Allocate a new json_tokener. + * When done using that to parse objects, free it with json_tokener_free(). + * See json_tokener_parse_ex() for usage details. + */ JSON_EXPORT struct json_tokener *json_tokener_new(void); + +/** + * Allocate a new json_tokener with a custom max nesting depth. + * @see JSON_TOKENER_DEFAULT_DEPTH + */ JSON_EXPORT struct json_tokener *json_tokener_new_ex(int depth); + +/** + * Free a json_tokener previously allocated with json_tokener_new(). + */ JSON_EXPORT void json_tokener_free(struct json_tokener *tok); + +/** + * Reset the state of a json_tokener, to prepare to parse a + * brand new JSON object. + */ JSON_EXPORT void json_tokener_reset(struct json_tokener *tok); + +/** + * Parse a json_object out of the string `str`. + * + * If you need more control over how the parsing occurs, + * see json_tokener_parse_ex(). + */ JSON_EXPORT struct json_object *json_tokener_parse(const char *str); + +/** + * Parser a json_object out of the string `str`, but if it fails + * return the error in `*error`. + * @see json_tokener_parse() + * @see json_tokener_parse_ex() + */ JSON_EXPORT struct json_object *json_tokener_parse_verbose(const char *str, enum json_tokener_error *error); From 6542d33cd1e546f9e58e7cba93049e2858ec9dc2 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 11 Jul 2020 15:03:00 +0000 Subject: [PATCH 54/94] Issue #641: Add a cast to void * to address some theoretically undefined printf behavior. --- json_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_object.c b/json_object.c index 73daa4c..2ee39ea 100644 --- a/json_object.c +++ b/json_object.c @@ -1635,7 +1635,7 @@ static int json_object_copy_serializer_data(struct json_object *src, struct json { _json_c_set_last_err( "json_object_deep_copy: unable to copy unknown serializer data: %p\n", - dst->_to_json_string); + (void *)dst->_to_json_string); return -1; } dst->_user_delete = src->_user_delete; From 2330c6f0de57356066881e1cdf1194ec03cdf01e Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 12 Jul 2020 17:55:46 +0000 Subject: [PATCH 55/94] Expand the doc for json_object_array_get_idx() to explain that it does not adjust refcounts. --- json_object.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/json_object.h b/json_object.h index 909c436..4121bf5 100644 --- a/json_object.h +++ b/json_object.h @@ -593,7 +593,15 @@ JSON_EXPORT int json_object_array_add(struct json_object *obj, struct json_objec JSON_EXPORT int json_object_array_put_idx(struct json_object *obj, size_t idx, struct json_object *val); -/** Get the element at specified index of the array (a json_object of type json_type_array) +/** Get the element at specified index of array `obj` (which must be a json_object of type json_type_array) + * + * *No* reference counts will be changed, and ownership of the returned + * object remains with `obj`. See json_object_object_get() for additional + * implications of this behavior. + * + * Calling this with anything other than a json_type_array will trigger + * an assert. + * * @param obj the json_object instance * @param idx the index to get the element at * @returns the json_object at the specified index (or NULL) From 4d9f6dd22e8437732e56db568438dd714ac8031b Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 12 Jul 2020 18:43:27 +0000 Subject: [PATCH 56/94] Issue #642: improve the docs for json_object_put() and json_object_get(). --- json_object.h | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/json_object.h b/json_object.h index 4121bf5..5cb85b0 100644 --- a/json_object.h +++ b/json_object.h @@ -133,21 +133,43 @@ extern "C" { /* reference counting functions */ /** - * Increment the reference count of json_object, thereby grabbing shared - * ownership of obj. + * Increment the reference count of json_object, thereby taking ownership of it. + * + * Cases where you might need to increase the refcount include: + * - Using an object field or array index (retrieved through + * `json_object_object_get()` or `json_object_array_get_idx()`) + * beyond the lifetime of the parent object. + * - Detaching an object field or array index from its parent object + * (using `json_object_object_del()` or `json_object_array_del_idx()`) + * - Sharing a json_object with multiple (not necesarily parallel) threads + * of execution that all expect to free it (with `json_object_put()`) when + * they're done. * * @param obj the json_object instance + * @see json_object_put() + * @see json_object_object_get() + * @see json_object_array_get_idx() */ JSON_EXPORT struct json_object *json_object_get(struct json_object *obj); /** * Decrement the reference count of json_object and free if it reaches zero. + * * You must have ownership of obj prior to doing this or you will cause an - * imbalance in the reference count. - * An obj of NULL may be passed; in that case this call is a no-op. + * imbalance in the reference count, leading to a classic use-after-free bug. + * In particular, you normally do not need to call `json_object_put()` on the + * json_object returned by `json_object_object_get()` or `json_object_array_get_idx()`. + * + * Just like after calling `free()` on a block of memory, you must not use + * `obj` after calling `json_object_put()` on it or any object that it + * is a member of (unless you know you've called `json_object_get(obj)` to + * explicitly increment the refcount). + * + * NULL may be passed, which which case this is a no-op. * * @param obj the json_object instance * @returns 1 if the object was freed. + * @see json_object_get() */ JSON_EXPORT int json_object_put(struct json_object *obj); @@ -347,7 +369,7 @@ JSON_C_CONST_FUNCTION(JSON_EXPORT size_t json_c_object_sizeof(void)); /** Add an object field to a json_object of type json_type_object * - * The reference count of `val` will *not* be incremented, in effect + * The reference count of `val` will *not* be incremented, in effect * transferring ownership that object to `obj`, and thus `val` will be * freed when `obj` is. (i.e. through `json_object_put(obj)`) * From 2508109b1881a2910e129b21039ef72e5e34e19d Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 12 Jul 2020 19:16:19 +0000 Subject: [PATCH 57/94] Remove the obsolete README.json_object-split.md, and mark README.md as being the doxygen mainpage. --- README.json_object-split.md | 15 --------------- README.md | 4 +++- 2 files changed, 3 insertions(+), 16 deletions(-) delete mode 100644 README.json_object-split.md diff --git a/README.json_object-split.md b/README.json_object-split.md deleted file mode 100644 index f0d8632..0000000 --- a/README.json_object-split.md +++ /dev/null @@ -1,15 +0,0 @@ - -This branch implements the changes briefly described at: - -https://github.com/json-c/json-c/wiki/Proposal:-struct-json_object-split - -These were originally mentioned in: -Issue #535 - short string optimization: excessive array length - -The changes are expected to impact and possibly invalidate: -Issue #552 - Some anlysis about memory allocator in json-c - -and will likely cause notable conflicts in any other significant un-merged -changes, such as PR#620 - Introduce json_object_new_string_{ext,noalloc}() - - diff --git a/README.md b/README.md index 3757a40..ff15eab 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +\mainpage + `json-c` ======== @@ -240,4 +242,4 @@ following more specific header files: * json_visit.h - Methods for walking a tree of json-c objects. * json_util.h - Miscelleanous utility functions. -For a full list of headers see [files.html](http://json-c.github.io/json-c/json-c-0.13.1/doc/html/files.html) +For a full list of headers see [files.html](http://json-c.github.io/json-c/json-c-current-release/doc/html/files.html) From cb10a13e94c39de47d44231f21831d623c36c8b0 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Fri, 17 Jul 2020 03:20:29 +0000 Subject: [PATCH 58/94] Remove the THIS_FUNCTION_IS_DEPRECATED define, we stopped using it long ago. --- json_object.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/json_object.h b/json_object.h index 5cb85b0..a54541c 100644 --- a/json_object.h +++ b/json_object.h @@ -17,16 +17,6 @@ #ifndef _json_object_h_ #define _json_object_h_ -#ifdef __GNUC__ -#define THIS_FUNCTION_IS_DEPRECATED(func) func __attribute__((deprecated)) -#elif defined(_MSC_VER) -#define THIS_FUNCTION_IS_DEPRECATED(func) __declspec(deprecated) func -#elif defined(__clang__) -#define THIS_FUNCTION_IS_DEPRECATED(func) func __deprecated -#else -#define THIS_FUNCTION_IS_DEPRECATED(func) func -#endif - #ifdef __GNUC__ #define JSON_C_CONST_FUNCTION(func) func __attribute__((const)) #else From 9a7de35b922d71f287590e1d0a5b602cdd22a0fa Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Fri, 17 Jul 2020 03:42:38 +0000 Subject: [PATCH 59/94] Add some more detail about how to use json-c in README.md. --- README.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ff15eab..fc128f5 100644 --- a/README.md +++ b/README.md @@ -238,8 +238,38 @@ following more specific header files: * json_tokener.h - Methods for parsing and serializing json-c object trees. * json_pointer.h - JSON Pointer (RFC 6901) implementation for retrieving objects from a json-c object tree. -* json_object_iterator.h - Methods for iterating over single json_object instances. +* json_object_iterator.h - Methods for iterating over single json_object instances. (See also `json_object_object_foreach()` in json_object.h) * json_visit.h - Methods for walking a tree of json-c objects. * json_util.h - Miscelleanous utility functions. For a full list of headers see [files.html](http://json-c.github.io/json-c/json-c-current-release/doc/html/files.html) + +The primary type in json-c is json_object. It describes a reference counted +tree of json objects which are created by either parsing text with a +json_tokener (i.e. `json_tokener_parse_ex()`), or by creating +(with `json_object_new_object()`, `json_object_new_int()`, etc...) and adding +(with `json_object_object_add()`, `json_object_array_add()`, etc...) them +individually. +Typically, every object in the tree will have one reference, from it's parent. +When you are done with the tree of objects, you call json_object_put() on just +the root object to free it, which recurses down through any child objects +calling json_object_put() on each one of those in turn. + +You can get a reference to a single child +(`json_object_object_get()` or `json_object_array_get_idx()`) +and use that object as long as its parent is valid. +If you need a child object to live longer than its parent, you can +increment the child's refcount (`json_object_get()`) to allow it to survive +the parent being freed or it being removed from its parent +(`json_object_object_del()` or `json_object_array_del_idx()`) + +When parsing text, the json_tokener object is independent from the json_object +that it returns. It can be allocated (`json_tokener_new()`) +used ones or multiple times (`json_tokener_parse_ex()`, and +freed (`json_tokener_free()`) while the json_object objects live on. + +A json_object tree can be serialized back into a string with +`json_object_to_json_string_ext()`. The string that is returned +is only valid until the next "to_json_string" call on that same object. +Also, it is freed when the json_object is freed. + From e46b9cdb7db8903aa20bb51369ec6abe6783e698 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Fri, 17 Jul 2020 03:46:21 +0000 Subject: [PATCH 60/94] Fix a number of things with the generated docs, including translating triple-backtick code blocks into a form doxygen understands. --- doc/Doxyfile.in | 16 +- doc/fixup_markdown.sh | 6 + issues_closed_for_0.13.md | 504 +++++++++++++++++++------------------- issues_closed_for_0.14.md | 372 ++++++++++++++-------------- 4 files changed, 457 insertions(+), 441 deletions(-) create mode 100755 doc/fixup_markdown.sh diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index ce8d8ff..1d489a7 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -805,7 +805,13 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = \ + */json_object_private.h \ + */debug.h \ + */*config.h \ + */random_seed.h \ + */strerror_*h \ + */*compat.h # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -816,7 +822,11 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = \ + _json_c_* \ + _LH_* \ + _printbuf_* \ + __STRING # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include @@ -859,7 +869,7 @@ IMAGE_PATH = # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. -INPUT_FILTER = +INPUT_FILTER = @CMAKE_CURRENT_SOURCE_DIR@/fixup_markdown.sh # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the diff --git a/doc/fixup_markdown.sh b/doc/fixup_markdown.sh new file mode 100755 index 0000000..452eb78 --- /dev/null +++ b/doc/fixup_markdown.sh @@ -0,0 +1,6 @@ +#!/bin/sh +# +# Doxygen markdown doesn't support triple-backticks like github does. +# Convert all of those to space-prefixed blocks instead. +# +awk '/```/ { prefix=!prefix; print ""; next; } { if (prefix) { printf " "; } print $0; } ' "$@" diff --git a/issues_closed_for_0.13.md b/issues_closed_for_0.13.md index c2b8f2d..f3e932c 100644 --- a/issues_closed_for_0.13.md +++ b/issues_closed_for_0.13.md @@ -16,255 +16,255 @@ Issues and Pull Requests closed for the 0.13 release (since commit f84d9c, the 0.12 branch point, 2014-04-10) -[Issue #61](https://github.com/json-c/json-c/issues/61) - Make json_object_object_add() indicate success or failure, test fix \ -[Issue #113](https://github.com/json-c/json-c/issues/113) - Build fixes (make dist and make distcheck) \ -[Issue #124](https://github.com/json-c/json-c/issues/124) - Fixing build \ -[Issue #125](https://github.com/json-c/json-c/issues/125) - Fix compile error(variable size set but not used) on g++4.6 \ -[Issue #126](https://github.com/json-c/json-c/issues/126) - Removed unused size variable. \ -[Issue #127](https://github.com/json-c/json-c/issues/127) - remove unused `size` variable \ -[Issue #128](https://github.com/json-c/json-c/issues/128) - Remove unused variable from json_tokenizer.c \ -[Issue #130](https://github.com/json-c/json-c/issues/130) - Failed to compile under Ubuntu 13.10 32bit \ -[Issue #131](https://github.com/json-c/json-c/issues/131) - undefined symbol: __sync_val_compare_and_swap_4 \ -[Issue #132](https://github.com/json-c/json-c/issues/132) - Remove unused variable 'size' \ -[Issue #133](https://github.com/json-c/json-c/issues/133) - Update and rename README to README.md \ -[Issue #134](https://github.com/json-c/json-c/issues/134) - Must remove variable size... \ -[Issue #135](https://github.com/json-c/json-c/issues/135) - bits.h uses removed json_tokener_errors\[error\] \ -[Issue #136](https://github.com/json-c/json-c/issues/136) - Error when running make check \ -[Issue #137](https://github.com/json-c/json-c/issues/137) - config.h.in should not be in git \ -[Issue #138](https://github.com/json-c/json-c/issues/138) - Can't build on RHEL 6.5 due to dependency on automake-1.14 \ -[Issue #140](https://github.com/json-c/json-c/issues/140) - Code bug in random_test.c evaluating same expression twice \ -[Issue #141](https://github.com/json-c/json-c/issues/141) - Removed duplicate check in random_seed test - bug #140 \ -[Issue #142](https://github.com/json-c/json-c/issues/142) - Please undeprecate json_object_object_get \ -[Issue #144](https://github.com/json-c/json-c/issues/144) - Introduce json_object_from_fd \ -[Issue #145](https://github.com/json-c/json-c/issues/145) - Handle % character properly \ -[Issue #146](https://github.com/json-c/json-c/issues/146) - TAGS rename \ -[Issue #148](https://github.com/json-c/json-c/issues/148) - Bump the soname \ -[Issue #149](https://github.com/json-c/json-c/issues/149) - SONAME bump \ -[Issue #150](https://github.com/json-c/json-c/issues/150) - Fix build using MinGW. \ -[Issue #151](https://github.com/json-c/json-c/issues/151) - Remove json_type enum trailing comma \ -[Issue #152](https://github.com/json-c/json-c/issues/152) - error while compiling json-c library version 0.11 \ -[Issue #153](https://github.com/json-c/json-c/issues/153) - improve doc for json_object_to_json_string() \ -[Issue #154](https://github.com/json-c/json-c/issues/154) - double precision \ -[Issue #155](https://github.com/json-c/json-c/issues/155) - add bsearch for arrays \ -[Issue #156](https://github.com/json-c/json-c/issues/156) - Remove trailing whitespaces \ -[Issue #157](https://github.com/json-c/json-c/issues/157) - JSON-C shall not exit on calloc fail. \ -[Issue #158](https://github.com/json-c/json-c/issues/158) - while using json-c 0.11, I am facing strange crash issue in json_object_put. \ -[Issue #159](https://github.com/json-c/json-c/issues/159) - json_tokener.c compile error \ -[Issue #160](https://github.com/json-c/json-c/issues/160) - missing header file on windows?? \ -[Issue #161](https://github.com/json-c/json-c/issues/161) - Is there a way to append to file? \ -[Issue #162](https://github.com/json-c/json-c/issues/162) - json_util: add directory check for POSIX distros \ -[Issue #163](https://github.com/json-c/json-c/issues/163) - Fix Win32 build problems \ -[Issue #164](https://github.com/json-c/json-c/issues/164) - made it compile and link on Widnows (as static library) \ -[Issue #165](https://github.com/json-c/json-c/issues/165) - json_object_to_json_string_ext length \ -[Issue #167](https://github.com/json-c/json-c/issues/167) - Can't build on Windows with Visual Studio 2010 \ -[Issue #168](https://github.com/json-c/json-c/issues/168) - Tightening the number parsing algorithm \ -[Issue #169](https://github.com/json-c/json-c/issues/169) - Doesn't compile on ubuntu 14.04, 64bit \ -[Issue #170](https://github.com/json-c/json-c/issues/170) - Generated files in repository \ -[Issue #171](https://github.com/json-c/json-c/issues/171) - Update configuration for VS2010 and win64 \ -[Issue #172](https://github.com/json-c/json-c/issues/172) - Adding support for parsing octal numbers \ -[Issue #173](https://github.com/json-c/json-c/issues/173) - json_parse_int64 doesn't work correctly at illumos \ -[Issue #174](https://github.com/json-c/json-c/issues/174) - Adding JSON_C_TO_STRING_PRETTY_TAB flag \ -[Issue #175](https://github.com/json-c/json-c/issues/175) - make check fails 4 tests with overflows when built with ASAN \ -[Issue #176](https://github.com/json-c/json-c/issues/176) - Possible to delete an array element at a given idx ? \ -[Issue #177](https://github.com/json-c/json-c/issues/177) - Fix compiler warnings \ -[Issue #178](https://github.com/json-c/json-c/issues/178) - Unable to compile on CentOS5 \ -[Issue #179](https://github.com/json-c/json-c/issues/179) - Added array_list_del_idx and json_object_array_del_idx \ -[Issue #180](https://github.com/json-c/json-c/issues/180) - Enable silent build by default \ -[Issue #181](https://github.com/json-c/json-c/issues/181) - json_tokener_parse_ex accepts invalid JSON \ -[Issue #182](https://github.com/json-c/json-c/issues/182) - Link against libm when needed \ -[Issue #183](https://github.com/json-c/json-c/issues/183) - Apply compile warning fix to master branch \ -[Issue #184](https://github.com/json-c/json-c/issues/184) - Use only GCC-specific flags when compiling with GCC \ -[Issue #185](https://github.com/json-c/json-c/issues/185) - compile error \ -[Issue #186](https://github.com/json-c/json-c/issues/186) - Syntax error \ -[Issue #187](https://github.com/json-c/json-c/issues/187) - array_list_get_idx and negative indexes. \ -[Issue #188](https://github.com/json-c/json-c/issues/188) - json_object_object_foreach warnings \ -[Issue #189](https://github.com/json-c/json-c/issues/189) - noisy json_object_from_file: error opening file \ -[Issue #190](https://github.com/json-c/json-c/issues/190) - warning: initialization discards const qualifier from pointer target type \[enabled by default\] \ -[Issue #192](https://github.com/json-c/json-c/issues/192) - json_tokener_parse accepts invalid JSON {"key": "value" , } \ -[Issue #193](https://github.com/json-c/json-c/issues/193) - Make serialization format of doubles configurable \ -[Issue #194](https://github.com/json-c/json-c/issues/194) - Add utility function for comparing json_objects \ -[Issue #195](https://github.com/json-c/json-c/issues/195) - Call uselocale instead of setlocale \ -[Issue #196](https://github.com/json-c/json-c/issues/196) - Performance improvements \ -[Issue #197](https://github.com/json-c/json-c/issues/197) - Time for a new release? \ -[Issue #198](https://github.com/json-c/json-c/issues/198) - Fix possible memory leak and remove superfluous NULL checks before free() \ -[Issue #199](https://github.com/json-c/json-c/issues/199) - Fix build in Visual Studio \ -[Issue #200](https://github.com/json-c/json-c/issues/200) - Add build scripts for CI platforms \ -[Issue #201](https://github.com/json-c/json-c/issues/201) - disable forward-slash escaping? \ -[Issue #202](https://github.com/json-c/json-c/issues/202) - Array with objects support \ -[Issue #203](https://github.com/json-c/json-c/issues/203) - Add source position/coordinates to API \ -[Issue #204](https://github.com/json-c/json-c/issues/204) - json-c/json.h not found \ -[Issue #205](https://github.com/json-c/json-c/issues/205) - json-c Compiled with Visual Studios \ -[Issue #206](https://github.com/json-c/json-c/issues/206) - what do i use in place of json_object_object_get? \ -[Issue #207](https://github.com/json-c/json-c/issues/207) - Add support for property pairs directly added to arrays \ -[Issue #208](https://github.com/json-c/json-c/issues/208) - Performance enhancements (mainly) to json_object_to_json_string() \ -[Issue #209](https://github.com/json-c/json-c/issues/209) - fix regression from 2d549662be832da838aa063da2efa78ee3b99668 \ -[Issue #210](https://github.com/json-c/json-c/issues/210) - Use size_t for arrays \ -[Issue #211](https://github.com/json-c/json-c/issues/211) - Atomic updates for the refcount \ -[Issue #212](https://github.com/json-c/json-c/issues/212) - Refcount doesn't work between threads \ -[Issue #213](https://github.com/json-c/json-c/issues/213) - fix to compile with microsoft visual c++ 2010 \ -[Issue #214](https://github.com/json-c/json-c/issues/214) - Some non-GNU systems support __sync_val_compare_and_swap \ -[Issue #215](https://github.com/json-c/json-c/issues/215) - Build json-c for window 64 bit. \ -[Issue #216](https://github.com/json-c/json-c/issues/216) - configure: check realloc with AC_CHECK_FUNCS() to fix cross-compilation. \ -[Issue #217](https://github.com/json-c/json-c/issues/217) - Checking for functions in float.h \ -[Issue #218](https://github.com/json-c/json-c/issues/218) - Use a macro to indicate C99 to the compiler \ -[Issue #219](https://github.com/json-c/json-c/issues/219) - Fix various potential null ptr deref and int32 overflows \ -[Issue #220](https://github.com/json-c/json-c/issues/220) - Add utility function for comparing json_objects \ -[Issue #221](https://github.com/json-c/json-c/issues/221) - JSON_C_TO_STRING_NOSLASHESCAPE works incorrectly \ -[Issue #222](https://github.com/json-c/json-c/issues/222) - Fix issue #221: JSON_C_TO_STRING_NOSLASHESCAPE works incorrectly \ -[Issue #223](https://github.com/json-c/json-c/issues/223) - Clarify json_object_get_string documentation of NULL handling & return \ -[Issue #224](https://github.com/json-c/json-c/issues/224) - json_tokener.c - all warnings being treated as errors \ -[Issue #225](https://github.com/json-c/json-c/issues/225) - Hi, will you support clib as a "registry"? \ -[Issue #227](https://github.com/json-c/json-c/issues/227) - Bump SOVERSION to 3 \ -[Issue #228](https://github.com/json-c/json-c/issues/228) - avoid double slashes from json \ -[Issue #229](https://github.com/json-c/json-c/issues/229) - configure fails: checking size of size_t... configure: error: cannot determine a size for size_t \ -[Issue #230](https://github.com/json-c/json-c/issues/230) - Use stdint.h to check for size_t size \ -[Issue #231](https://github.com/json-c/json-c/issues/231) - Fix size_t size check for first-time builds \ -[Issue #232](https://github.com/json-c/json-c/issues/232) - tests/tests1: fix printf format for size_t arguments \ -[Issue #233](https://github.com/json-c/json-c/issues/233) - Include stddef.h in json_object.h \ -[Issue #234](https://github.com/json-c/json-c/issues/234) - Add public API to use userdata independently of custom serializer \ -[Issue #235](https://github.com/json-c/json-c/issues/235) - Undefined symbols Error for architecture x86_64 on Mac \ -[Issue #236](https://github.com/json-c/json-c/issues/236) - Building a project which uses json-c with flag -Wcast-qual causes compilation errors \ -[Issue #237](https://github.com/json-c/json-c/issues/237) - handle escaped utf-8 \ -[Issue #238](https://github.com/json-c/json-c/issues/238) - linkhash.c: optimised the table_free path \ -[Issue #239](https://github.com/json-c/json-c/issues/239) - initialize null terminator of new printbuf \ -[Issue #240](https://github.com/json-c/json-c/issues/240) - Compile error: Variable set but not used \ -[Issue #241](https://github.com/json-c/json-c/issues/241) - getting error in date string 19\/07\/2016, fixed for error 19/07/2016 \ -[Issue #242](https://github.com/json-c/json-c/issues/242) - json_tokener_parse error \ -[Issue #243](https://github.com/json-c/json-c/issues/243) - Fix #165 \ -[Issue #244](https://github.com/json-c/json-c/issues/244) - Error while compiling source from RHEL5, could you please help me to fix this \ -[Issue #245](https://github.com/json-c/json-c/issues/245) - json-c compile in window xp \ -[Issue #246](https://github.com/json-c/json-c/issues/246) - Mac: uselocale failed to build \ -[Issue #247](https://github.com/json-c/json-c/issues/247) - json_object_array_del_idx function has segment fault error? \ -[Issue #248](https://github.com/json-c/json-c/issues/248) - Minor changes in C source code \ -[Issue #249](https://github.com/json-c/json-c/issues/249) - Improving README \ -[Issue #250](https://github.com/json-c/json-c/issues/250) - Improving .gitignore \ -[Issue #251](https://github.com/json-c/json-c/issues/251) - Adding a file for EditorConfig \ -[Issue #252](https://github.com/json-c/json-c/issues/252) - Very minor changes not related to C source code \ -[Issue #253](https://github.com/json-c/json-c/issues/253) - Adding a test with cppcheck for Travis CI \ -[Issue #254](https://github.com/json-c/json-c/issues/254) - Very minor changes to some tests \ -[Issue #255](https://github.com/json-c/json-c/issues/255) - Minor changes in C source code \ -[Issue #256](https://github.com/json-c/json-c/issues/256) - Mailing list dead? \ -[Issue #257](https://github.com/json-c/json-c/issues/257) - Defining a coding style \ -[Issue #258](https://github.com/json-c/json-c/issues/258) - Enable CI services \ -[Issue #259](https://github.com/json-c/json-c/issues/259) - Fails to parse valid json \ -[Issue #260](https://github.com/json-c/json-c/issues/260) - Adding an object to itself \ -[Issue #261](https://github.com/json-c/json-c/issues/261) - Lack of proper documentation \ -[Issue #262](https://github.com/json-c/json-c/issues/262) - Add Cmakefile and fix compiler warning. \ -[Issue #263](https://github.com/json-c/json-c/issues/263) - Compiler Warnings with VS2015 \ -[Issue #264](https://github.com/json-c/json-c/issues/264) - successed in simple test while failed in my project \ -[Issue #265](https://github.com/json-c/json-c/issues/265) - Conformance report for reference \ -[Issue #266](https://github.com/json-c/json-c/issues/266) - crash perhaps related to reference counting \ -[Issue #267](https://github.com/json-c/json-c/issues/267) - Removes me as Win32 maintainer, because I'm not. \ -[Issue #268](https://github.com/json-c/json-c/issues/268) - Documentation of json_object_to_json_string gives no information about memory management \ -[Issue #269](https://github.com/json-c/json-c/issues/269) - json_object__set(json_object *o, value) API for value setting in json object private structure \ -[Issue #270](https://github.com/json-c/json-c/issues/270) - new API json_object_new_double_f(doubel d,const char * fmt); \ -[Issue #271](https://github.com/json-c/json-c/issues/271) - Cannot compile using CMake on macOS \ -[Issue #273](https://github.com/json-c/json-c/issues/273) - fixed wrong object name in json_object_all_values_equal \ -[Issue #274](https://github.com/json-c/json-c/issues/274) - Support for 64 bit pointers on Windows \ -[Issue #275](https://github.com/json-c/json-c/issues/275) - Out-of-bounds read in json_tokener_parse_ex \ -[Issue #276](https://github.com/json-c/json-c/issues/276) - ./configure for centos release 6.7(final) failure \ -[Issue #277](https://github.com/json-c/json-c/issues/277) - Json object set xxx \ -[Issue #278](https://github.com/json-c/json-c/issues/278) - Serialization of double with no fractional component drops trailing zero \ -[Issue #279](https://github.com/json-c/json-c/issues/279) - Segmentation fault in array_list_length() \ -[Issue #280](https://github.com/json-c/json-c/issues/280) - Should json_object_array_get_idx check whether input obj is array? \ -[Issue #281](https://github.com/json-c/json-c/issues/281) - how to pretty print json-c? \ -[Issue #282](https://github.com/json-c/json-c/issues/282) - ignore temporary files \ -[Issue #283](https://github.com/json-c/json-c/issues/283) - json_pointer: add first revision based on RFC 6901 \ -[Issue #284](https://github.com/json-c/json-c/issues/284) - Resusing json_tokener object \ -[Issue #285](https://github.com/json-c/json-c/issues/285) - Revert "compat/strdup.h: move common compat check for strdup() to own \ -[Issue #286](https://github.com/json-c/json-c/issues/286) - json_tokener_parse_ex() returns json_tokener_continue on zero-length string \ -[Issue #287](https://github.com/json-c/json-c/issues/287) - json_pointer: extend setter & getter with printf() style arguments \ -[Issue #288](https://github.com/json-c/json-c/issues/288) - Fix _GNU_SOURCE define for vasprintf \ -[Issue #289](https://github.com/json-c/json-c/issues/289) - bugfix: floating point representaion without fractional part \ -[Issue #290](https://github.com/json-c/json-c/issues/290) - duplicate an json_object \ -[Issue #291](https://github.com/json-c/json-c/issues/291) - isspace assert error \ -[Issue #292](https://github.com/json-c/json-c/issues/292) - configure error "./configure: line 13121: syntax error near unexpected token `-Wall'" \ -[Issue #293](https://github.com/json-c/json-c/issues/293) - how to make with bitcode for ios \ -[Issue #294](https://github.com/json-c/json-c/issues/294) - Adding UTF-8 validation. Fixes #122 \ -[Issue #295](https://github.com/json-c/json-c/issues/295) - cross compile w/ mingw \ -[Issue #296](https://github.com/json-c/json-c/issues/296) - Missing functions header in json_object.h \ -[Issue #297](https://github.com/json-c/json-c/issues/297) - could not parse string to Json object? Like string str=\"helloworld;E\\test\\log\\;end\" \ -[Issue #298](https://github.com/json-c/json-c/issues/298) - Building using CMake doesn't work \ -[Issue #299](https://github.com/json-c/json-c/issues/299) - Improve json_object -> string performance \ -[Issue #300](https://github.com/json-c/json-c/issues/300) - Running tests with MinGW build \ -[Issue #301](https://github.com/json-c/json-c/issues/301) - How to deep copy json_object in C++ ? \ -[Issue #302](https://github.com/json-c/json-c/issues/302) - json_tokener_parse_ex doesn't parse JSON values \ -[Issue #303](https://github.com/json-c/json-c/issues/303) - fix doc in tokener header file \ -[Issue #304](https://github.com/json-c/json-c/issues/304) - (.text+0x72846): undefined reference to `is_error' \ -[Issue #305](https://github.com/json-c/json-c/issues/305) - Fix compilation without C-99 option \ -[Issue #306](https://github.com/json-c/json-c/issues/306) - ./configure: line 12748 -error=deprecated-declarations \ -[Issue #307](https://github.com/json-c/json-c/issues/307) - Memory leak in json_tokener_parse \ -[Issue #308](https://github.com/json-c/json-c/issues/308) - AM_PROG_LIBTOOL not found on Linux \ -[Issue #309](https://github.com/json-c/json-c/issues/309) - GCC 7 reports various -Wimplicit-fallthrough= errors \ -[Issue #310](https://github.com/json-c/json-c/issues/310) - Add FALLTHRU comment to handle GCC7 warnings. \ -[Issue #311](https://github.com/json-c/json-c/issues/311) - Fix error C3688 when compiling on Visual Studio 2015 \ -[Issue #312](https://github.com/json-c/json-c/issues/312) - Fix CMake Build process improved for MinGW and MSYS2 \ -[Issue #313](https://github.com/json-c/json-c/issues/313) - VERBOSE=1 make check; tests/test_util_file.test.c and tests/test_util_file.expected out of sync \ -[Issue #315](https://github.com/json-c/json-c/issues/315) - Passing -1 to json_tokener_parse_ex is possibly unsafe \ -[Issue #316](https://github.com/json-c/json-c/issues/316) - Memory Returned by json_object_to_json_string not freed \ -[Issue #317](https://github.com/json-c/json-c/issues/317) - json_object_get_string gives segmentation error \ -[Issue #318](https://github.com/json-c/json-c/issues/318) - PVS-Studio static analyzer analyze results \ -[Issue #319](https://github.com/json-c/json-c/issues/319) - Windows: Fix dynamic library build with Visual Studio \ -[Issue #320](https://github.com/json-c/json-c/issues/320) - Can't compile in Mac OS X El Capitan \ -[Issue #321](https://github.com/json-c/json-c/issues/321) - build,cmake: fix vasprintf implicit definition and generate both static & shared libs \ -[Issue #322](https://github.com/json-c/json-c/issues/322) - can not link with libjson-c.a \ -[Issue #323](https://github.com/json-c/json-c/issues/323) - implicit fallthrough detected by gcc 7.1 \ -[Issue #324](https://github.com/json-c/json-c/issues/324) - JsonPath like function? \ -[Issue #325](https://github.com/json-c/json-c/issues/325) - Fix stack buffer overflow in json_object_double_to_json_string_format() \ -[Issue #327](https://github.com/json-c/json-c/issues/327) - why json-c so hard to compile \ -[Issue #328](https://github.com/json-c/json-c/issues/328) - json_object: implement json_object_deep_copy() function \ -[Issue #329](https://github.com/json-c/json-c/issues/329) - build,cmake: build,cmake: rename libjson-c-static.a to libjson-c.a \ -[Issue #330](https://github.com/json-c/json-c/issues/330) - tests: symlink basic tests to a single file that has the common code \ -[Issue #331](https://github.com/json-c/json-c/issues/331) - Safe use of snprintf() / vsnprintf() for Visual studio, and thread-safety fix \ -[Issue #332](https://github.com/json-c/json-c/issues/332) - Valgrind: invalid read after json_object_array_del_idx. \ -[Issue #333](https://github.com/json-c/json-c/issues/333) - Replace obsolete AM_PROG_LIBTOOL \ -[Issue #335](https://github.com/json-c/json-c/issues/335) - README.md: show build status tag from travis-ci.org \ -[Issue #336](https://github.com/json-c/json-c/issues/336) - tests: fix tests in travis-ci.org \ -[Issue #337](https://github.com/json-c/json-c/issues/337) - Synchronize "potentially racy" random seed in lh_char_hash() \ -[Issue #338](https://github.com/json-c/json-c/issues/338) - implement json_object_int_inc(json_object *, int64_t) \ -[Issue #339](https://github.com/json-c/json-c/issues/339) - Json schema validation \ -[Issue #340](https://github.com/json-c/json-c/issues/340) - strerror_override: add extern "C" and JSON_EXPORT specifiers for Visual C++ compilers \ -[Issue #341](https://github.com/json-c/json-c/issues/341) - character "/" parse as "\/" \ -[Issue #342](https://github.com/json-c/json-c/issues/342) - No such file or directory "/usr/include/json.h" \ -[Issue #343](https://github.com/json-c/json-c/issues/343) - Can't parse json \ -[Issue #344](https://github.com/json-c/json-c/issues/344) - Fix Mingw build \ -[Issue #345](https://github.com/json-c/json-c/issues/345) - Fix make dist and make distcheck \ -[Issue #346](https://github.com/json-c/json-c/issues/346) - Clamp double to int32 when narrowing in json_object_get_int. \ -[Issue #347](https://github.com/json-c/json-c/issues/347) - MSVC linker error json_c_strerror \ -[Issue #348](https://github.com/json-c/json-c/issues/348) - why \ -[Issue #349](https://github.com/json-c/json-c/issues/349) - `missing` is missing? \ -[Issue #350](https://github.com/json-c/json-c/issues/350) - stderror-override and disable-shared \ -[Issue #351](https://github.com/json-c/json-c/issues/351) - SIZE_T_MAX redefined from limits.h \ -[Issue #352](https://github.com/json-c/json-c/issues/352) - `INSTALL` overrides an automake script. \ -[Issue #353](https://github.com/json-c/json-c/issues/353) - Documentation issues \ -[Issue #354](https://github.com/json-c/json-c/issues/354) - Fixes #351 #352 #353 \ -[Issue #355](https://github.com/json-c/json-c/issues/355) - 1.make it can been compiled with Visual Studio 2010 by modify the CMakeList.txt and others \ -[Issue #356](https://github.com/json-c/json-c/issues/356) - VS2008 test test_util_file.cpp err! \ -[Issue #357](https://github.com/json-c/json-c/issues/357) - __json_c_strerror incompatibility with link-time optimization \ -[Issue #358](https://github.com/json-c/json-c/issues/358) - make issue \ -[Issue #359](https://github.com/json-c/json-c/issues/359) - update CMakeLists.txt for compile with visual studio at least 2010 \ -[Issue #360](https://github.com/json-c/json-c/issues/360) - Use strtoll() to parse ints \ -[Issue #361](https://github.com/json-c/json-c/issues/361) - Fix double to int cast overflow in json_object_get_int64. \ -[Issue #362](https://github.com/json-c/json-c/issues/362) - CMake Package Config \ -[Issue #363](https://github.com/json-c/json-c/issues/363) - Issue #338, add json_object_add_int functions \ -[Issue #364](https://github.com/json-c/json-c/issues/364) - Cmake is Errir \ -[Issue #365](https://github.com/json-c/json-c/issues/365) - added fallthrough for gcc7 \ -[Issue #366](https://github.com/json-c/json-c/issues/366) - how to check the json string,crash! \ -[Issue #367](https://github.com/json-c/json-c/issues/367) - Is json-c support "redirect" semantic? \ -[Issue #368](https://github.com/json-c/json-c/issues/368) - Add examples \ -[Issue #369](https://github.com/json-c/json-c/issues/369) - How to build json-c library for android? \ -[Issue #370](https://github.com/json-c/json-c/issues/370) - Compiling using clang-cl \ -[Issue #371](https://github.com/json-c/json-c/issues/371) - Invalid parsing for Infinity with json-c 0.12 \ -[Issue #372](https://github.com/json-c/json-c/issues/372) - Json-c 0.12: Fixed Infinity bug \ -[Issue #373](https://github.com/json-c/json-c/issues/373) - build: fix build on appveyor CI \ -[Issue #374](https://github.com/json-c/json-c/issues/374) - Undefined symbols for architecture x86_64: \ -[Issue #375](https://github.com/json-c/json-c/issues/375) - what would happened when json_object_object_add add the same key \ -[Issue #376](https://github.com/json-c/json-c/issues/376) - Eclipse error \ -[Issue #377](https://github.com/json-c/json-c/issues/377) - on gcc 7.2.0 on my linux distribution with json-c 2013-04-02 source \ -[Issue #378](https://github.com/json-c/json-c/issues/378) - Eclipse: library (libjson-c) not found, but configured \ -[Issue #379](https://github.com/json-c/json-c/issues/379) - error: this statement may fall through \[-Werror=implicit-fallthrough=\] \ -[Issue #380](https://github.com/json-c/json-c/issues/380) - Build on Windows \ -[Issue #381](https://github.com/json-c/json-c/issues/381) - Fix makedist \ -[Issue #382](https://github.com/json-c/json-c/issues/382) - Memory leak for json_tokener_parse_ex for version 0.12.1 \ -[Issue #383](https://github.com/json-c/json-c/issues/383) - Fix a compiler warning. \ -[Issue #384](https://github.com/json-c/json-c/issues/384) - Fix a VS 2015 compiler warnings. \ +* [Issue #61](https://github.com/json-c/json-c/issues/61) - Make json_object_object_add() indicate success or failure, test fix \ +* [Issue #113](https://github.com/json-c/json-c/issues/113) - Build fixes (make dist and make distcheck) \ +* [Issue #124](https://github.com/json-c/json-c/issues/124) - Fixing build \ +* [Issue #125](https://github.com/json-c/json-c/issues/125) - Fix compile error(variable size set but not used) on g++4.6 \ +* [Issue #126](https://github.com/json-c/json-c/issues/126) - Removed unused size variable. \ +* [Issue #127](https://github.com/json-c/json-c/issues/127) - remove unused `size` variable \ +* [Issue #128](https://github.com/json-c/json-c/issues/128) - Remove unused variable from json_tokenizer.c \ +* [Issue #130](https://github.com/json-c/json-c/issues/130) - Failed to compile under Ubuntu 13.10 32bit \ +* [Issue #131](https://github.com/json-c/json-c/issues/131) - undefined symbol: __sync_val_compare_and_swap_4 \ +* [Issue #132](https://github.com/json-c/json-c/issues/132) - Remove unused variable 'size' \ +* [Issue #133](https://github.com/json-c/json-c/issues/133) - Update and rename README to README.md \ +* [Issue #134](https://github.com/json-c/json-c/issues/134) - Must remove variable size... \ +* [Issue #135](https://github.com/json-c/json-c/issues/135) - bits.h uses removed json_tokener_errors\[error\] \ +* [Issue #136](https://github.com/json-c/json-c/issues/136) - Error when running make check \ +* [Issue #137](https://github.com/json-c/json-c/issues/137) - config.h.in should not be in git \ +* [Issue #138](https://github.com/json-c/json-c/issues/138) - Can't build on RHEL 6.5 due to dependency on automake-1.14 \ +* [Issue #140](https://github.com/json-c/json-c/issues/140) - Code bug in random_test.c evaluating same expression twice \ +* [Issue #141](https://github.com/json-c/json-c/issues/141) - Removed duplicate check in random_seed test - bug #140 \ +* [Issue #142](https://github.com/json-c/json-c/issues/142) - Please undeprecate json_object_object_get \ +* [Issue #144](https://github.com/json-c/json-c/issues/144) - Introduce json_object_from_fd \ +* [Issue #145](https://github.com/json-c/json-c/issues/145) - Handle % character properly \ +* [Issue #146](https://github.com/json-c/json-c/issues/146) - TAGS rename \ +* [Issue #148](https://github.com/json-c/json-c/issues/148) - Bump the soname \ +* [Issue #149](https://github.com/json-c/json-c/issues/149) - SONAME bump \ +* [Issue #150](https://github.com/json-c/json-c/issues/150) - Fix build using MinGW. \ +* [Issue #151](https://github.com/json-c/json-c/issues/151) - Remove json_type enum trailing comma \ +* [Issue #152](https://github.com/json-c/json-c/issues/152) - error while compiling json-c library version 0.11 \ +* [Issue #153](https://github.com/json-c/json-c/issues/153) - improve doc for json_object_to_json_string() \ +* [Issue #154](https://github.com/json-c/json-c/issues/154) - double precision \ +* [Issue #155](https://github.com/json-c/json-c/issues/155) - add bsearch for arrays \ +* [Issue #156](https://github.com/json-c/json-c/issues/156) - Remove trailing whitespaces \ +* [Issue #157](https://github.com/json-c/json-c/issues/157) - JSON-C shall not exit on calloc fail. \ +* [Issue #158](https://github.com/json-c/json-c/issues/158) - while using json-c 0.11, I am facing strange crash issue in json_object_put. \ +* [Issue #159](https://github.com/json-c/json-c/issues/159) - json_tokener.c compile error \ +* [Issue #160](https://github.com/json-c/json-c/issues/160) - missing header file on windows?? \ +* [Issue #161](https://github.com/json-c/json-c/issues/161) - Is there a way to append to file? \ +* [Issue #162](https://github.com/json-c/json-c/issues/162) - json_util: add directory check for POSIX distros \ +* [Issue #163](https://github.com/json-c/json-c/issues/163) - Fix Win32 build problems \ +* [Issue #164](https://github.com/json-c/json-c/issues/164) - made it compile and link on Widnows (as static library) \ +* [Issue #165](https://github.com/json-c/json-c/issues/165) - json_object_to_json_string_ext length \ +* [Issue #167](https://github.com/json-c/json-c/issues/167) - Can't build on Windows with Visual Studio 2010 \ +* [Issue #168](https://github.com/json-c/json-c/issues/168) - Tightening the number parsing algorithm \ +* [Issue #169](https://github.com/json-c/json-c/issues/169) - Doesn't compile on ubuntu 14.04, 64bit \ +* [Issue #170](https://github.com/json-c/json-c/issues/170) - Generated files in repository \ +* [Issue #171](https://github.com/json-c/json-c/issues/171) - Update configuration for VS2010 and win64 \ +* [Issue #172](https://github.com/json-c/json-c/issues/172) - Adding support for parsing octal numbers \ +* [Issue #173](https://github.com/json-c/json-c/issues/173) - json_parse_int64 doesn't work correctly at illumos \ +* [Issue #174](https://github.com/json-c/json-c/issues/174) - Adding JSON_C_TO_STRING_PRETTY_TAB flag \ +* [Issue #175](https://github.com/json-c/json-c/issues/175) - make check fails 4 tests with overflows when built with ASAN \ +* [Issue #176](https://github.com/json-c/json-c/issues/176) - Possible to delete an array element at a given idx ? \ +* [Issue #177](https://github.com/json-c/json-c/issues/177) - Fix compiler warnings \ +* [Issue #178](https://github.com/json-c/json-c/issues/178) - Unable to compile on CentOS5 \ +* [Issue #179](https://github.com/json-c/json-c/issues/179) - Added array_list_del_idx and json_object_array_del_idx \ +* [Issue #180](https://github.com/json-c/json-c/issues/180) - Enable silent build by default \ +* [Issue #181](https://github.com/json-c/json-c/issues/181) - json_tokener_parse_ex accepts invalid JSON \ +* [Issue #182](https://github.com/json-c/json-c/issues/182) - Link against libm when needed \ +* [Issue #183](https://github.com/json-c/json-c/issues/183) - Apply compile warning fix to master branch \ +* [Issue #184](https://github.com/json-c/json-c/issues/184) - Use only GCC-specific flags when compiling with GCC \ +* [Issue #185](https://github.com/json-c/json-c/issues/185) - compile error \ +* [Issue #186](https://github.com/json-c/json-c/issues/186) - Syntax error \ +* [Issue #187](https://github.com/json-c/json-c/issues/187) - array_list_get_idx and negative indexes. \ +* [Issue #188](https://github.com/json-c/json-c/issues/188) - json_object_object_foreach warnings \ +* [Issue #189](https://github.com/json-c/json-c/issues/189) - noisy json_object_from_file: error opening file \ +* [Issue #190](https://github.com/json-c/json-c/issues/190) - warning: initialization discards const qualifier from pointer target type \[enabled by default\] \ +* [Issue #192](https://github.com/json-c/json-c/issues/192) - json_tokener_parse accepts invalid JSON {"key": "value" , } \ +* [Issue #193](https://github.com/json-c/json-c/issues/193) - Make serialization format of doubles configurable \ +* [Issue #194](https://github.com/json-c/json-c/issues/194) - Add utility function for comparing json_objects \ +* [Issue #195](https://github.com/json-c/json-c/issues/195) - Call uselocale instead of setlocale \ +* [Issue #196](https://github.com/json-c/json-c/issues/196) - Performance improvements \ +* [Issue #197](https://github.com/json-c/json-c/issues/197) - Time for a new release? \ +* [Issue #198](https://github.com/json-c/json-c/issues/198) - Fix possible memory leak and remove superfluous NULL checks before free() \ +* [Issue #199](https://github.com/json-c/json-c/issues/199) - Fix build in Visual Studio \ +* [Issue #200](https://github.com/json-c/json-c/issues/200) - Add build scripts for CI platforms \ +* [Issue #201](https://github.com/json-c/json-c/issues/201) - disable forward-slash escaping? \ +* [Issue #202](https://github.com/json-c/json-c/issues/202) - Array with objects support \ +* [Issue #203](https://github.com/json-c/json-c/issues/203) - Add source position/coordinates to API \ +* [Issue #204](https://github.com/json-c/json-c/issues/204) - json-c/json.h not found \ +* [Issue #205](https://github.com/json-c/json-c/issues/205) - json-c Compiled with Visual Studios \ +* [Issue #206](https://github.com/json-c/json-c/issues/206) - what do i use in place of json_object_object_get? \ +* [Issue #207](https://github.com/json-c/json-c/issues/207) - Add support for property pairs directly added to arrays \ +* [Issue #208](https://github.com/json-c/json-c/issues/208) - Performance enhancements (mainly) to json_object_to_json_string() \ +* [Issue #209](https://github.com/json-c/json-c/issues/209) - fix regression from 2d549662be832da838aa063da2efa78ee3b99668 \ +* [Issue #210](https://github.com/json-c/json-c/issues/210) - Use size_t for arrays \ +* [Issue #211](https://github.com/json-c/json-c/issues/211) - Atomic updates for the refcount \ +* [Issue #212](https://github.com/json-c/json-c/issues/212) - Refcount doesn't work between threads \ +* [Issue #213](https://github.com/json-c/json-c/issues/213) - fix to compile with microsoft visual c++ 2010 \ +* [Issue #214](https://github.com/json-c/json-c/issues/214) - Some non-GNU systems support __sync_val_compare_and_swap \ +* [Issue #215](https://github.com/json-c/json-c/issues/215) - Build json-c for window 64 bit. \ +* [Issue #216](https://github.com/json-c/json-c/issues/216) - configure: check realloc with AC_CHECK_FUNCS() to fix cross-compilation. \ +* [Issue #217](https://github.com/json-c/json-c/issues/217) - Checking for functions in float.h \ +* [Issue #218](https://github.com/json-c/json-c/issues/218) - Use a macro to indicate C99 to the compiler \ +* [Issue #219](https://github.com/json-c/json-c/issues/219) - Fix various potential null ptr deref and int32 overflows \ +* [Issue #220](https://github.com/json-c/json-c/issues/220) - Add utility function for comparing json_objects \ +* [Issue #221](https://github.com/json-c/json-c/issues/221) - JSON_C_TO_STRING_NOSLASHESCAPE works incorrectly \ +* [Issue #222](https://github.com/json-c/json-c/issues/222) - Fix issue #221: JSON_C_TO_STRING_NOSLASHESCAPE works incorrectly \ +* [Issue #223](https://github.com/json-c/json-c/issues/223) - Clarify json_object_get_string documentation of NULL handling & return \ +* [Issue #224](https://github.com/json-c/json-c/issues/224) - json_tokener.c - all warnings being treated as errors \ +* [Issue #225](https://github.com/json-c/json-c/issues/225) - Hi, will you support clib as a "registry"? \ +* [Issue #227](https://github.com/json-c/json-c/issues/227) - Bump SOVERSION to 3 \ +* [Issue #228](https://github.com/json-c/json-c/issues/228) - avoid double slashes from json \ +* [Issue #229](https://github.com/json-c/json-c/issues/229) - configure fails: checking size of size_t... configure: error: cannot determine a size for size_t \ +* [Issue #230](https://github.com/json-c/json-c/issues/230) - Use stdint.h to check for size_t size \ +* [Issue #231](https://github.com/json-c/json-c/issues/231) - Fix size_t size check for first-time builds \ +* [Issue #232](https://github.com/json-c/json-c/issues/232) - tests/tests1: fix printf format for size_t arguments \ +* [Issue #233](https://github.com/json-c/json-c/issues/233) - Include stddef.h in json_object.h \ +* [Issue #234](https://github.com/json-c/json-c/issues/234) - Add public API to use userdata independently of custom serializer \ +* [Issue #235](https://github.com/json-c/json-c/issues/235) - Undefined symbols Error for architecture x86_64 on Mac \ +* [Issue #236](https://github.com/json-c/json-c/issues/236) - Building a project which uses json-c with flag -Wcast-qual causes compilation errors \ +* [Issue #237](https://github.com/json-c/json-c/issues/237) - handle escaped utf-8 \ +* [Issue #238](https://github.com/json-c/json-c/issues/238) - linkhash.c: optimised the table_free path \ +* [Issue #239](https://github.com/json-c/json-c/issues/239) - initialize null terminator of new printbuf \ +* [Issue #240](https://github.com/json-c/json-c/issues/240) - Compile error: Variable set but not used \ +* [Issue #241](https://github.com/json-c/json-c/issues/241) - getting error in date string 19\/07\/2016, fixed for error 19/07/2016 \ +* [Issue #242](https://github.com/json-c/json-c/issues/242) - json_tokener_parse error \ +* [Issue #243](https://github.com/json-c/json-c/issues/243) - Fix #165 \ +* [Issue #244](https://github.com/json-c/json-c/issues/244) - Error while compiling source from RHEL5, could you please help me to fix this \ +* [Issue #245](https://github.com/json-c/json-c/issues/245) - json-c compile in window xp \ +* [Issue #246](https://github.com/json-c/json-c/issues/246) - Mac: uselocale failed to build \ +* [Issue #247](https://github.com/json-c/json-c/issues/247) - json_object_array_del_idx function has segment fault error? \ +* [Issue #248](https://github.com/json-c/json-c/issues/248) - Minor changes in C source code \ +* [Issue #249](https://github.com/json-c/json-c/issues/249) - Improving README \ +* [Issue #250](https://github.com/json-c/json-c/issues/250) - Improving .gitignore \ +* [Issue #251](https://github.com/json-c/json-c/issues/251) - Adding a file for EditorConfig \ +* [Issue #252](https://github.com/json-c/json-c/issues/252) - Very minor changes not related to C source code \ +* [Issue #253](https://github.com/json-c/json-c/issues/253) - Adding a test with cppcheck for Travis CI \ +* [Issue #254](https://github.com/json-c/json-c/issues/254) - Very minor changes to some tests \ +* [Issue #255](https://github.com/json-c/json-c/issues/255) - Minor changes in C source code \ +* [Issue #256](https://github.com/json-c/json-c/issues/256) - Mailing list dead? \ +* [Issue #257](https://github.com/json-c/json-c/issues/257) - Defining a coding style \ +* [Issue #258](https://github.com/json-c/json-c/issues/258) - Enable CI services \ +* [Issue #259](https://github.com/json-c/json-c/issues/259) - Fails to parse valid json \ +* [Issue #260](https://github.com/json-c/json-c/issues/260) - Adding an object to itself \ +* [Issue #261](https://github.com/json-c/json-c/issues/261) - Lack of proper documentation \ +* [Issue #262](https://github.com/json-c/json-c/issues/262) - Add Cmakefile and fix compiler warning. \ +* [Issue #263](https://github.com/json-c/json-c/issues/263) - Compiler Warnings with VS2015 \ +* [Issue #264](https://github.com/json-c/json-c/issues/264) - successed in simple test while failed in my project \ +* [Issue #265](https://github.com/json-c/json-c/issues/265) - Conformance report for reference \ +* [Issue #266](https://github.com/json-c/json-c/issues/266) - crash perhaps related to reference counting \ +* [Issue #267](https://github.com/json-c/json-c/issues/267) - Removes me as Win32 maintainer, because I'm not. \ +* [Issue #268](https://github.com/json-c/json-c/issues/268) - Documentation of json_object_to_json_string gives no information about memory management \ +* [Issue #269](https://github.com/json-c/json-c/issues/269) - json_object__set(json_object *o, value) API for value setting in json object private structure \ +* [Issue #270](https://github.com/json-c/json-c/issues/270) - new API json_object_new_double_f(doubel d,const char * fmt); \ +* [Issue #271](https://github.com/json-c/json-c/issues/271) - Cannot compile using CMake on macOS \ +* [Issue #273](https://github.com/json-c/json-c/issues/273) - fixed wrong object name in json_object_all_values_equal \ +* [Issue #274](https://github.com/json-c/json-c/issues/274) - Support for 64 bit pointers on Windows \ +* [Issue #275](https://github.com/json-c/json-c/issues/275) - Out-of-bounds read in json_tokener_parse_ex \ +* [Issue #276](https://github.com/json-c/json-c/issues/276) - ./configure for centos release 6.7(final) failure \ +* [Issue #277](https://github.com/json-c/json-c/issues/277) - Json object set xxx \ +* [Issue #278](https://github.com/json-c/json-c/issues/278) - Serialization of double with no fractional component drops trailing zero \ +* [Issue #279](https://github.com/json-c/json-c/issues/279) - Segmentation fault in array_list_length() \ +* [Issue #280](https://github.com/json-c/json-c/issues/280) - Should json_object_array_get_idx check whether input obj is array? \ +* [Issue #281](https://github.com/json-c/json-c/issues/281) - how to pretty print json-c? \ +* [Issue #282](https://github.com/json-c/json-c/issues/282) - ignore temporary files \ +* [Issue #283](https://github.com/json-c/json-c/issues/283) - json_pointer: add first revision based on RFC 6901 \ +* [Issue #284](https://github.com/json-c/json-c/issues/284) - Resusing json_tokener object \ +* [Issue #285](https://github.com/json-c/json-c/issues/285) - Revert "compat/strdup.h: move common compat check for strdup() to own \ +* [Issue #286](https://github.com/json-c/json-c/issues/286) - json_tokener_parse_ex() returns json_tokener_continue on zero-length string \ +* [Issue #287](https://github.com/json-c/json-c/issues/287) - json_pointer: extend setter & getter with printf() style arguments \ +* [Issue #288](https://github.com/json-c/json-c/issues/288) - Fix _GNU_SOURCE define for vasprintf \ +* [Issue #289](https://github.com/json-c/json-c/issues/289) - bugfix: floating point representaion without fractional part \ +* [Issue #290](https://github.com/json-c/json-c/issues/290) - duplicate an json_object \ +* [Issue #291](https://github.com/json-c/json-c/issues/291) - isspace assert error \ +* [Issue #292](https://github.com/json-c/json-c/issues/292) - configure error "./configure: line 13121: syntax error near unexpected token `-Wall'" \ +* [Issue #293](https://github.com/json-c/json-c/issues/293) - how to make with bitcode for ios \ +* [Issue #294](https://github.com/json-c/json-c/issues/294) - Adding UTF-8 validation. Fixes #122 \ +* [Issue #295](https://github.com/json-c/json-c/issues/295) - cross compile w/ mingw \ +* [Issue #296](https://github.com/json-c/json-c/issues/296) - Missing functions header in json_object.h \ +* [Issue #297](https://github.com/json-c/json-c/issues/297) - could not parse string to Json object? Like string str=\"helloworld;E\\test\\log\\;end\" \ +* [Issue #298](https://github.com/json-c/json-c/issues/298) - Building using CMake doesn't work \ +* [Issue #299](https://github.com/json-c/json-c/issues/299) - Improve json_object -> string performance \ +* [Issue #300](https://github.com/json-c/json-c/issues/300) - Running tests with MinGW build \ +* [Issue #301](https://github.com/json-c/json-c/issues/301) - How to deep copy json_object in C++ ? \ +* [Issue #302](https://github.com/json-c/json-c/issues/302) - json_tokener_parse_ex doesn't parse JSON values \ +* [Issue #303](https://github.com/json-c/json-c/issues/303) - fix doc in tokener header file \ +* [Issue #304](https://github.com/json-c/json-c/issues/304) - (.text+0x72846): undefined reference to `is_error' \ +* [Issue #305](https://github.com/json-c/json-c/issues/305) - Fix compilation without C-99 option \ +* [Issue #306](https://github.com/json-c/json-c/issues/306) - ./configure: line 12748 -error=deprecated-declarations \ +* [Issue #307](https://github.com/json-c/json-c/issues/307) - Memory leak in json_tokener_parse \ +* [Issue #308](https://github.com/json-c/json-c/issues/308) - AM_PROG_LIBTOOL not found on Linux \ +* [Issue #309](https://github.com/json-c/json-c/issues/309) - GCC 7 reports various -Wimplicit-fallthrough= errors \ +* [Issue #310](https://github.com/json-c/json-c/issues/310) - Add FALLTHRU comment to handle GCC7 warnings. \ +* [Issue #311](https://github.com/json-c/json-c/issues/311) - Fix error C3688 when compiling on Visual Studio 2015 \ +* [Issue #312](https://github.com/json-c/json-c/issues/312) - Fix CMake Build process improved for MinGW and MSYS2 \ +* [Issue #313](https://github.com/json-c/json-c/issues/313) - VERBOSE=1 make check; tests/test_util_file.test.c and tests/test_util_file.expected out of sync \ +* [Issue #315](https://github.com/json-c/json-c/issues/315) - Passing -1 to json_tokener_parse_ex is possibly unsafe \ +* [Issue #316](https://github.com/json-c/json-c/issues/316) - Memory Returned by json_object_to_json_string not freed \ +* [Issue #317](https://github.com/json-c/json-c/issues/317) - json_object_get_string gives segmentation error \ +* [Issue #318](https://github.com/json-c/json-c/issues/318) - PVS-Studio static analyzer analyze results \ +* [Issue #319](https://github.com/json-c/json-c/issues/319) - Windows: Fix dynamic library build with Visual Studio \ +* [Issue #320](https://github.com/json-c/json-c/issues/320) - Can't compile in Mac OS X El Capitan \ +* [Issue #321](https://github.com/json-c/json-c/issues/321) - build,cmake: fix vasprintf implicit definition and generate both static & shared libs \ +* [Issue #322](https://github.com/json-c/json-c/issues/322) - can not link with libjson-c.a \ +* [Issue #323](https://github.com/json-c/json-c/issues/323) - implicit fallthrough detected by gcc 7.1 \ +* [Issue #324](https://github.com/json-c/json-c/issues/324) - JsonPath like function? \ +* [Issue #325](https://github.com/json-c/json-c/issues/325) - Fix stack buffer overflow in json_object_double_to_json_string_format() \ +* [Issue #327](https://github.com/json-c/json-c/issues/327) - why json-c so hard to compile \ +* [Issue #328](https://github.com/json-c/json-c/issues/328) - json_object: implement json_object_deep_copy() function \ +* [Issue #329](https://github.com/json-c/json-c/issues/329) - build,cmake: build,cmake: rename libjson-c-static.a to libjson-c.a \ +* [Issue #330](https://github.com/json-c/json-c/issues/330) - tests: symlink basic tests to a single file that has the common code \ +* [Issue #331](https://github.com/json-c/json-c/issues/331) - Safe use of snprintf() / vsnprintf() for Visual studio, and thread-safety fix \ +* [Issue #332](https://github.com/json-c/json-c/issues/332) - Valgrind: invalid read after json_object_array_del_idx. \ +* [Issue #333](https://github.com/json-c/json-c/issues/333) - Replace obsolete AM_PROG_LIBTOOL \ +* [Issue #335](https://github.com/json-c/json-c/issues/335) - README.md: show build status tag from travis-ci.org \ +* [Issue #336](https://github.com/json-c/json-c/issues/336) - tests: fix tests in travis-ci.org \ +* [Issue #337](https://github.com/json-c/json-c/issues/337) - Synchronize "potentially racy" random seed in lh_char_hash() \ +* [Issue #338](https://github.com/json-c/json-c/issues/338) - implement json_object_int_inc(json_object *, int64_t) \ +* [Issue #339](https://github.com/json-c/json-c/issues/339) - Json schema validation \ +* [Issue #340](https://github.com/json-c/json-c/issues/340) - strerror_override: add extern "C" and JSON_EXPORT specifiers for Visual C++ compilers \ +* [Issue #341](https://github.com/json-c/json-c/issues/341) - character "/" parse as "\/" \ +* [Issue #342](https://github.com/json-c/json-c/issues/342) - No such file or directory "/usr/include/json.h" \ +* [Issue #343](https://github.com/json-c/json-c/issues/343) - Can't parse json \ +* [Issue #344](https://github.com/json-c/json-c/issues/344) - Fix Mingw build \ +* [Issue #345](https://github.com/json-c/json-c/issues/345) - Fix make dist and make distcheck \ +* [Issue #346](https://github.com/json-c/json-c/issues/346) - Clamp double to int32 when narrowing in json_object_get_int. \ +* [Issue #347](https://github.com/json-c/json-c/issues/347) - MSVC linker error json_c_strerror \ +* [Issue #348](https://github.com/json-c/json-c/issues/348) - why \ +* [Issue #349](https://github.com/json-c/json-c/issues/349) - `missing` is missing? \ +* [Issue #350](https://github.com/json-c/json-c/issues/350) - stderror-override and disable-shared \ +* [Issue #351](https://github.com/json-c/json-c/issues/351) - SIZE_T_MAX redefined from limits.h \ +* [Issue #352](https://github.com/json-c/json-c/issues/352) - `INSTALL` overrides an automake script. \ +* [Issue #353](https://github.com/json-c/json-c/issues/353) - Documentation issues \ +* [Issue #354](https://github.com/json-c/json-c/issues/354) - Fixes #351 #352 #353 \ +* [Issue #355](https://github.com/json-c/json-c/issues/355) - 1.make it can been compiled with Visual Studio 2010 by modify the CMakeList.txt and others \ +* [Issue #356](https://github.com/json-c/json-c/issues/356) - VS2008 test test_util_file.cpp err! \ +* [Issue #357](https://github.com/json-c/json-c/issues/357) - __json_c_strerror incompatibility with link-time optimization \ +* [Issue #358](https://github.com/json-c/json-c/issues/358) - make issue \ +* [Issue #359](https://github.com/json-c/json-c/issues/359) - update CMakeLists.txt for compile with visual studio at least 2010 \ +* [Issue #360](https://github.com/json-c/json-c/issues/360) - Use strtoll() to parse ints \ +* [Issue #361](https://github.com/json-c/json-c/issues/361) - Fix double to int cast overflow in json_object_get_int64. \ +* [Issue #362](https://github.com/json-c/json-c/issues/362) - CMake Package Config \ +* [Issue #363](https://github.com/json-c/json-c/issues/363) - Issue #338, add json_object_add_int functions \ +* [Issue #364](https://github.com/json-c/json-c/issues/364) - Cmake is Errir \ +* [Issue #365](https://github.com/json-c/json-c/issues/365) - added fallthrough for gcc7 \ +* [Issue #366](https://github.com/json-c/json-c/issues/366) - how to check the json string,crash! \ +* [Issue #367](https://github.com/json-c/json-c/issues/367) - Is json-c support "redirect" semantic? \ +* [Issue #368](https://github.com/json-c/json-c/issues/368) - Add examples \ +* [Issue #369](https://github.com/json-c/json-c/issues/369) - How to build json-c library for android? \ +* [Issue #370](https://github.com/json-c/json-c/issues/370) - Compiling using clang-cl \ +* [Issue #371](https://github.com/json-c/json-c/issues/371) - Invalid parsing for Infinity with json-c 0.12 \ +* [Issue #372](https://github.com/json-c/json-c/issues/372) - Json-c 0.12: Fixed Infinity bug \ +* [Issue #373](https://github.com/json-c/json-c/issues/373) - build: fix build on appveyor CI \ +* [Issue #374](https://github.com/json-c/json-c/issues/374) - Undefined symbols for architecture x86_64: \ +* [Issue #375](https://github.com/json-c/json-c/issues/375) - what would happened when json_object_object_add add the same key \ +* [Issue #376](https://github.com/json-c/json-c/issues/376) - Eclipse error \ +* [Issue #377](https://github.com/json-c/json-c/issues/377) - on gcc 7.2.0 on my linux distribution with json-c 2013-04-02 source \ +* [Issue #378](https://github.com/json-c/json-c/issues/378) - Eclipse: library (libjson-c) not found, but configured \ +* [Issue #379](https://github.com/json-c/json-c/issues/379) - error: this statement may fall through \[-Werror=implicit-fallthrough=\] \ +* [Issue #380](https://github.com/json-c/json-c/issues/380) - Build on Windows \ +* [Issue #381](https://github.com/json-c/json-c/issues/381) - Fix makedist \ +* [Issue #382](https://github.com/json-c/json-c/issues/382) - Memory leak for json_tokener_parse_ex for version 0.12.1 \ +* [Issue #383](https://github.com/json-c/json-c/issues/383) - Fix a compiler warning. \ +* [Issue #384](https://github.com/json-c/json-c/issues/384) - Fix a VS 2015 compiler warnings. \ diff --git a/issues_closed_for_0.14.md b/issues_closed_for_0.14.md index bca934a..65096f0 100644 --- a/issues_closed_for_0.14.md +++ b/issues_closed_for_0.14.md @@ -14,189 +14,189 @@ sed -e's,^\[ *\(.*\)\](https://api.github.com/.*/\([0-9].*\)),[Issue #\2](https: Issues and Pull Requests closed for the 0.14 release (since commit d582d3a(2017-12-07) to a911439(2020-04-17)) -[Issue #122](https://github.com/json-c/json-c/issues/122) - Add utf-8 validation when parsing strings. \ -[Issue #139](https://github.com/json-c/json-c/issues/139) - json_object_from_file cannot accept max_depth \ -[Issue #143](https://github.com/json-c/json-c/issues/143) - RFE / enhancement for full 64-bit signed/unsigned support \ -[Issue #147](https://github.com/json-c/json-c/issues/147) - Please introduce soname bump if API changed \ -[Issue #166](https://github.com/json-c/json-c/issues/166) - Need a way to specify nesting depth when opening JSON file \ -[Issue #226](https://github.com/json-c/json-c/issues/226) - There is no json_object_new_null() \ -[Issue #314](https://github.com/json-c/json-c/issues/314) - new release ? \ -[Issue #326](https://github.com/json-c/json-c/issues/326) - Please extend api json_object_get_uint64 \ -[Issue #334](https://github.com/json-c/json-c/issues/334) - Switch json-c builds to use CMake \ -[Issue #386](https://github.com/json-c/json-c/issues/386) - Makefile: Add ACLOCAL_AMFLAGS \ -[Issue #387](https://github.com/json-c/json-c/issues/387) - doc: Use other doxygen feature to specify mainpage \ -[Issue #388](https://github.com/json-c/json-c/issues/388) - json_object: Add size_t json_object_sizeof() \ -[Issue #389](https://github.com/json-c/json-c/issues/389) - json_object: Avoid double free (and thus a segfault) when ref_count gets < 0 \ -[Issue #390](https://github.com/json-c/json-c/issues/390) - json_object: Add const size_t json_c_object_sizeof() \ -[Issue #391](https://github.com/json-c/json-c/issues/391) - Fix non-GNUC define for JSON_C_CONST_FUNCTION \ -[Issue #392](https://github.com/json-c/json-c/issues/392) - json_object: Avoid invalid free (and thus a segfault) when ref_count gets < 0 \ -[Issue #393](https://github.com/json-c/json-c/issues/393) - json_object_private: Use unsigned 32-bit integer type for refcount \ -[Issue #394](https://github.com/json-c/json-c/issues/394) - Problem serializing double \ -[Issue #395](https://github.com/json-c/json-c/issues/395) - Key gets modified if it contains "\" \ -[Issue #396](https://github.com/json-c/json-c/issues/396) - Build failure with no threads uClibc toolchain \ -[Issue #397](https://github.com/json-c/json-c/issues/397) - update json object with key. \ -[Issue #398](https://github.com/json-c/json-c/issues/398) - Build failed. \ -[Issue #399](https://github.com/json-c/json-c/issues/399) - Avoid uninitialized variable warnings \ -[Issue #400](https://github.com/json-c/json-c/issues/400) - How to generate static lib (.a) \ -[Issue #401](https://github.com/json-c/json-c/issues/401) - Warnings with Valgrind \ -[Issue #402](https://github.com/json-c/json-c/issues/402) - Add fuzzers from OSS-Fuzz \ -[Issue #403](https://github.com/json-c/json-c/issues/403) - Segmentation fault when double quotes is used \ -[Issue #404](https://github.com/json-c/json-c/issues/404) - valgrind: memory leak \ -[Issue #405](https://github.com/json-c/json-c/issues/405) - Missing API to determine an object is empty \ -[Issue #406](https://github.com/json-c/json-c/issues/406) - Undefine NDEBUG for tests \ -[Issue #407](https://github.com/json-c/json-c/issues/407) - json_tokener_parse is crash \ -[Issue #408](https://github.com/json-c/json-c/issues/408) - bug in array_list_del_idx when array_list_length()==1 \ -[Issue #410](https://github.com/json-c/json-c/issues/410) - Fixed typos \ -[Issue #411](https://github.com/json-c/json-c/issues/411) - Crash- signal SIGSEGV, Segmentation fault. ../sysdeps/x86_64/strlen.S: No such file or directory. \ -[Issue #412](https://github.com/json-c/json-c/issues/412) - json_type changes during inter process communication. \ -[Issue #413](https://github.com/json-c/json-c/issues/413) - how to read object of type `json_object *` in c++ \ -[Issue #414](https://github.com/json-c/json-c/issues/414) - [Question] How JSON-c stores the serialized data in memory? \ -[Issue #415](https://github.com/json-c/json-c/issues/415) - Resolve windows name conflict \ -[Issue #416](https://github.com/json-c/json-c/issues/416) - segmentation fault in json_tokener_parse \ -[Issue #417](https://github.com/json-c/json-c/issues/417) - json_tokener_parse json_object_object_get_ex with string value which is json string \ -[Issue #418](https://github.com/json-c/json-c/issues/418) - json_object_from_* return value documented incorrectly \ -[Issue #419](https://github.com/json-c/json-c/issues/419) - Suggestion: document (and define) that json_object_put() accepts NULL pointer to object \ -[Issue #420](https://github.com/json-c/json-c/issues/420) - arraylist: Fixed names of parameters for callback function \ -[Issue #421](https://github.com/json-c/json-c/issues/421) - install json_object_iterator.h header file \ -[Issue #422](https://github.com/json-c/json-c/issues/422) - json_object_get_double() does not set errno when there is no valid conversion \ -[Issue #423](https://github.com/json-c/json-c/issues/423) - memory leak \ -[Issue #424](https://github.com/json-c/json-c/issues/424) - Parse string contains "\" or "/" errors \ -[Issue #425](https://github.com/json-c/json-c/issues/425) - what this is? \ -[Issue #426](https://github.com/json-c/json-c/issues/426) - __deprecated not supported on clang. \ -[Issue #427](https://github.com/json-c/json-c/issues/427) - CMake: builds involving this target will not be correct \ -[Issue #430](https://github.com/json-c/json-c/issues/430) - json_object_object_del() and Segmentation fault \ -[Issue #431](https://github.com/json-c/json-c/issues/431) - cmake: Bump required version \ -[Issue #432](https://github.com/json-c/json-c/issues/432) - The real CMake support. \ -[Issue #433](https://github.com/json-c/json-c/issues/433) - The real CMake support. \ -[Issue #434](https://github.com/json-c/json-c/issues/434) - The real CMake support \ -[Issue #435](https://github.com/json-c/json-c/issues/435) - json_object_object_del() segmentation fault \ -[Issue #436](https://github.com/json-c/json-c/issues/436) - Improve pkgconfig setting \ -[Issue #437](https://github.com/json-c/json-c/issues/437) - Bad link in README.md \ -[Issue #438](https://github.com/json-c/json-c/issues/438) - Bad link in README.html \ -[Issue #439](https://github.com/json-c/json-c/issues/439) - reserved identifier violation \ -[Issue #440](https://github.com/json-c/json-c/issues/440) - Use of angle brackets around file names for include statements \ -[Issue #441](https://github.com/json-c/json-c/issues/441) - fix c flag loss during cmake building \ -[Issue #442](https://github.com/json-c/json-c/issues/442) - error in configure file \ -[Issue #443](https://github.com/json-c/json-c/issues/443) - remove pretty spaces when using pretty tabs \ -[Issue #444](https://github.com/json-c/json-c/issues/444) - Document refcount of json_tokener_parse_ex return \ -[Issue #445](https://github.com/json-c/json-c/issues/445) - Add missing "make check" target to cmake config \ -[Issue #446](https://github.com/json-c/json-c/issues/446) - Forward slashes get escaped \ -[Issue #448](https://github.com/json-c/json-c/issues/448) - Buffer overflow in json-c \ -[Issue #449](https://github.com/json-c/json-c/issues/449) - Need of json_type_int64 returned by json_object_get_type() \ -[Issue #450](https://github.com/json-c/json-c/issues/450) - Allow use json-c cmake as subproject \ -[Issue #452](https://github.com/json-c/json-c/issues/452) - Update README.md \ -[Issue #453](https://github.com/json-c/json-c/issues/453) - Fixed misalignment in JSON string due to space after \n being printed... \ -[Issue #454](https://github.com/json-c/json-c/issues/454) - json_object_private: save 8 bytes in struct json_object in 64-bit arc… \ -[Issue #455](https://github.com/json-c/json-c/issues/455) - index.html:fix dead link \ -[Issue #456](https://github.com/json-c/json-c/issues/456) - STYLE.txt:remove executable permissions \ -[Issue #457](https://github.com/json-c/json-c/issues/457) - .gitignore:add build directory \ -[Issue #458](https://github.com/json-c/json-c/issues/458) - README.md:fix dead "file.html" link \ -[Issue #459](https://github.com/json-c/json-c/issues/459) - README.html:fix link to Doxygen docs, remove WIN32 link \ -[Issue #460](https://github.com/json-c/json-c/issues/460) - No docs for json_object_new_string_len() \ -[Issue #461](https://github.com/json-c/json-c/issues/461) - json_object.c:set errno in json_object_get_double() \ -[Issue #462](https://github.com/json-c/json-c/issues/462) - json_object.h:document json_object_new_string_len() \ -[Issue #463](https://github.com/json-c/json-c/issues/463) - please check newlocale api first argument valuse. \ -[Issue #465](https://github.com/json-c/json-c/issues/465) - CMakeLists.txt doesn't contain json_object_iterator.h which json.h includes \ -[Issue #466](https://github.com/json-c/json-c/issues/466) - configure:3610: error: C compiler cannot create executables \ -[Issue #467](https://github.com/json-c/json-c/issues/467) - Fix compiler warnings \ -[Issue #468](https://github.com/json-c/json-c/issues/468) - Fix compiler warnings \ -[Issue #469](https://github.com/json-c/json-c/issues/469) - Build under alpine with pecl install & docker-php-ext-enable? \ -[Issue #470](https://github.com/json-c/json-c/issues/470) - cfuhash_foreach_remove doesn't upate cfuhash_num_entries \ -[Issue #472](https://github.com/json-c/json-c/issues/472) - Segmentation fault in json_object_iter_begin \ -[Issue #473](https://github.com/json-c/json-c/issues/473) - Convert ChangeLog to valid UTF-8 encoding. \ -[Issue #474](https://github.com/json-c/json-c/issues/474) - Installation directories empty with CMake in pkg-config. \ -[Issue #475](https://github.com/json-c/json-c/issues/475) - improvement proposal for json_object_object_foreach \ -[Issue #477](https://github.com/json-c/json-c/issues/477) - Hang/Crash with large strings \ -[Issue #478](https://github.com/json-c/json-c/issues/478) - json_object_get_string_len returns 0 when value is number \ -[Issue #479](https://github.com/json-c/json-c/issues/479) - I want to use it in iOS or Android but I can't compile \ -[Issue #480](https://github.com/json-c/json-c/issues/480) - json-c-0.12.1 failed making from source code \ -[Issue #481](https://github.com/json-c/json-c/issues/481) - error while loading shared libraries: libjson-c.so.4 \ -[Issue #482](https://github.com/json-c/json-c/issues/482) - Error "double free or corruption" after free() \ -[Issue #483](https://github.com/json-c/json-c/issues/483) - compatible with rarely-used Chinese characters in GBK charset \ -[Issue #485](https://github.com/json-c/json-c/issues/485) - Install CMake module files \ -[Issue #486](https://github.com/json-c/json-c/issues/486) - In the case of negative double value, it is formatted without including ".0" \ -[Issue #488](https://github.com/json-c/json-c/issues/488) - Some APIs are not exported when built as shared lib on Win32 \ -[Issue #489](https://github.com/json-c/json-c/issues/489) - Don't use -Werror by default \ -[Issue #490](https://github.com/json-c/json-c/issues/490) - do not compile with -Werror by default \ -[Issue #491](https://github.com/json-c/json-c/issues/491) - build: add option --disable-werror to configure \ -[Issue #492](https://github.com/json-c/json-c/issues/492) - lack some quick usage in readme \ -[Issue #494](https://github.com/json-c/json-c/issues/494) - Code generator? \ -[Issue #495](https://github.com/json-c/json-c/issues/495) - README.md:fix 2 typos \ -[Issue #496](https://github.com/json-c/json-c/issues/496) - json_pointer.h:suggest minor grammar improvement for pointer doc \ -[Issue #497](https://github.com/json-c/json-c/issues/497) - add common header for all tests \ -[Issue #498](https://github.com/json-c/json-c/issues/498) - double_serializer_test fails (with valgrind) \ -[Issue #499](https://github.com/json-c/json-c/issues/499) - .travis.yml:test on more recent clang and gcc versions \ -[Issue #500](https://github.com/json-c/json-c/issues/500) - test/Makefile.am:add missing deps for test1 and test2 \ -[Issue #501](https://github.com/json-c/json-c/issues/501) - undefine NDEBUG for tests \ -[Issue #502](https://github.com/json-c/json-c/issues/502) - configure error \ -[Issue #503](https://github.com/json-c/json-c/issues/503) - json-c retuns OK when Invalid json string is passed \ -[Issue #504](https://github.com/json-c/json-c/issues/504) - json_object_put coredump \ -[Issue #505](https://github.com/json-c/json-c/issues/505) - Add vcpkg installation instructions \ -[Issue #506](https://github.com/json-c/json-c/issues/506) - Cannot parse more than one object \ -[Issue #509](https://github.com/json-c/json-c/issues/509) - Sometimes a double value is not serialized \ -[Issue #510](https://github.com/json-c/json-c/issues/510) - Bump so-name and improve CMake \ -[Issue #511](https://github.com/json-c/json-c/issues/511) - Reduce lines for better optimization \ -[Issue #512](https://github.com/json-c/json-c/issues/512) - Properly append to CMAKE_C_FLAGS string \ -[Issue #513](https://github.com/json-c/json-c/issues/513) - What does `userdata` means?And what is the case we can use it? \ -[Issue #514](https://github.com/json-c/json-c/issues/514) - Json c 0.13 \ -[Issue #515](https://github.com/json-c/json-c/issues/515) - Mies suomesta fixes segfaults and logic errors \ -[Issue #516](https://github.com/json-c/json-c/issues/516) - Lja slight mods \ -[Issue #518](https://github.com/json-c/json-c/issues/518) - Escape character "\\003\", get unexpected value \ -[Issue #519](https://github.com/json-c/json-c/issues/519) - Add test case obj token \ -[Issue #520](https://github.com/json-c/json-c/issues/520) - Adding type uint64 \ -[Issue #521](https://github.com/json-c/json-c/issues/521) - build cmake windows 10 \ -[Issue #522](https://github.com/json-c/json-c/issues/522) - update json_visit testcase \ -[Issue #523](https://github.com/json-c/json-c/issues/523) - update tsetcase for tokener_c \ -[Issue #524](https://github.com/json-c/json-c/issues/524) - Increase coverage \ -[Issue #525](https://github.com/json-c/json-c/issues/525) - update pointer test case \ -[Issue #526](https://github.com/json-c/json-c/issues/526) - Increased the test coverage of printbuf.c 82% to 92%. \ -[Issue #527](https://github.com/json-c/json-c/issues/527) - Arraylist testcase \ -[Issue #528](https://github.com/json-c/json-c/issues/528) - Solve issue #108. Skip \u0000 while parsing. \ -[Issue #529](https://github.com/json-c/json-c/issues/529) - Increased the test coverage of json_c_version.c 0% to 100%. \ -[Issue #530](https://github.com/json-c/json-c/issues/530) - validate utf-8 string before parse \ -[Issue #531](https://github.com/json-c/json-c/issues/531) - validate utf-8 string \ -[Issue #532](https://github.com/json-c/json-c/issues/532) - json_object_object_get_ex returning the original object \ -[Issue #533](https://github.com/json-c/json-c/issues/533) - Fix "make check" \ -[Issue #535](https://github.com/json-c/json-c/issues/535) - short string optimization: excessive array length \ -[Issue #536](https://github.com/json-c/json-c/issues/536) - add json_object_new_null() \ -[Issue #538](https://github.com/json-c/json-c/issues/538) - update shortstring and arraylist parameters \ -[Issue #539](https://github.com/json-c/json-c/issues/539) - double serializes to the old value after set_double \ -[Issue #541](https://github.com/json-c/json-c/issues/541) - add coveralls auto tool to json-c \ -[Issue #542](https://github.com/json-c/json-c/issues/542) - add uint64 data to json-c \ -[Issue #543](https://github.com/json-c/json-c/issues/543) - Readme \ -[Issue #544](https://github.com/json-c/json-c/issues/544) - Increase distcheck target in cmake \ -[Issue #545](https://github.com/json-c/json-c/issues/545) - add doc target in cmake \ -[Issue #546](https://github.com/json-c/json-c/issues/546) - Add uninstall target in cmake \ -[Issue #547](https://github.com/json-c/json-c/issues/547) - modify json-c default build type, and fix up the assert() errors in t… \ -[Issue #548](https://github.com/json-c/json-c/issues/548) - Solve some problems about cmake build type (debug/release) \ -[Issue #549](https://github.com/json-c/json-c/issues/549) - lib installation issues \ -[Issue #550](https://github.com/json-c/json-c/issues/550) - Format codes with clang-format tool? \ -[Issue #551](https://github.com/json-c/json-c/issues/551) - Allow hexadecimal number format convention parsing \ -[Issue #553](https://github.com/json-c/json-c/issues/553) - Fix/clang ubsan \ -[Issue #554](https://github.com/json-c/json-c/issues/554) - RFC 8259 compatibility mode \ -[Issue #555](https://github.com/json-c/json-c/issues/555) - Format json-c with clang-format tool \ -[Issue #556](https://github.com/json-c/json-c/issues/556) - Fixes various Wreturn-type and Wimplicit-fallthrough errors on Mingw-w64 \ -[Issue #557](https://github.com/json-c/json-c/issues/557) - Add option in CMAKE to not build documentation \ -[Issue #558](https://github.com/json-c/json-c/issues/558) - modify the doc target message \ -[Issue #559](https://github.com/json-c/json-c/issues/559) - json_c_visit() not exported on Windows \ -[Issue #560](https://github.com/json-c/json-c/issues/560) - error: implicit declaration of function '_strtoi64' \ -[Issue #561](https://github.com/json-c/json-c/issues/561) - add the badge in README.md and test the coveralls \ -[Issue #562](https://github.com/json-c/json-c/issues/562) - Bugfix and testcases supplements \ -[Issue #563](https://github.com/json-c/json-c/issues/563) - Changed order of calloc args to match stdlib \ -[Issue #564](https://github.com/json-c/json-c/issues/564) - Remove autogenerated files \ -[Issue #565](https://github.com/json-c/json-c/issues/565) - test the CI and ignore this PR \ -[Issue #566](https://github.com/json-c/json-c/issues/566) - add the json_types.h to Makefile.am \ -[Issue #567](https://github.com/json-c/json-c/issues/567) - Install json_types.h with autotools build as well. \ -[Issue #568](https://github.com/json-c/json-c/issues/568) - Adding better support to MinGW \ -[Issue #569](https://github.com/json-c/json-c/issues/569) - Handling of -Bsymbolic-function in CMakeLists.txt is deficient \ -[Issue #571](https://github.com/json-c/json-c/issues/571) - CMake: Bump SONAME to 5. \ -[Issue #572](https://github.com/json-c/json-c/issues/572) - Small fixes to CMakeLists \ -[Issue #573](https://github.com/json-c/json-c/issues/573) - Fix coveralls submission. \ -[Issue #574](https://github.com/json-c/json-c/issues/574) - autogen.sh missing from repository \ -[Issue #575](https://github.com/json-c/json-c/issues/575) - Small cosmetics. \ -[Issue #576](https://github.com/json-c/json-c/issues/576) - Test coverage for json_c_version. \ -[Issue #577](https://github.com/json-c/json-c/issues/577) - Be verbose on failing json_c_version test. \ -[Issue #578](https://github.com/json-c/json-c/issues/578) - CMake: Install pkgconfig file in proper location by default \ -[Issue #579](https://github.com/json-c/json-c/issues/579) - Enforce strict prototypes. \ -[Issue #580](https://github.com/json-c/json-c/issues/580) - Fix CMake tests for enforced strict prototypes. \ -[Issue #581](https://github.com/json-c/json-c/issues/581) - CMakeLists: do not enforce strict prototypes on Windows. \ +* [Issue #122](https://github.com/json-c/json-c/issues/122) - Add utf-8 validation when parsing strings. \ +* [Issue #139](https://github.com/json-c/json-c/issues/139) - json_object_from_file cannot accept max_depth \ +* [Issue #143](https://github.com/json-c/json-c/issues/143) - RFE / enhancement for full 64-bit signed/unsigned support \ +* [Issue #147](https://github.com/json-c/json-c/issues/147) - Please introduce soname bump if API changed \ +* [Issue #166](https://github.com/json-c/json-c/issues/166) - Need a way to specify nesting depth when opening JSON file \ +* [Issue #226](https://github.com/json-c/json-c/issues/226) - There is no json_object_new_null() \ +* [Issue #314](https://github.com/json-c/json-c/issues/314) - new release ? \ +* [Issue #326](https://github.com/json-c/json-c/issues/326) - Please extend api json_object_get_uint64 \ +* [Issue #334](https://github.com/json-c/json-c/issues/334) - Switch json-c builds to use CMake \ +* [Issue #386](https://github.com/json-c/json-c/issues/386) - Makefile: Add ACLOCAL_AMFLAGS \ +* [Issue #387](https://github.com/json-c/json-c/issues/387) - doc: Use other doxygen feature to specify mainpage \ +* [Issue #388](https://github.com/json-c/json-c/issues/388) - json_object: Add size_t json_object_sizeof() \ +* [Issue #389](https://github.com/json-c/json-c/issues/389) - json_object: Avoid double free (and thus a segfault) when ref_count gets < 0 \ +* [Issue #390](https://github.com/json-c/json-c/issues/390) - json_object: Add const size_t json_c_object_sizeof() \ +* [Issue #391](https://github.com/json-c/json-c/issues/391) - Fix non-GNUC define for JSON_C_CONST_FUNCTION \ +* [Issue #392](https://github.com/json-c/json-c/issues/392) - json_object: Avoid invalid free (and thus a segfault) when ref_count gets < 0 \ +* [Issue #393](https://github.com/json-c/json-c/issues/393) - json_object_private: Use unsigned 32-bit integer type for refcount \ +* [Issue #394](https://github.com/json-c/json-c/issues/394) - Problem serializing double \ +* [Issue #395](https://github.com/json-c/json-c/issues/395) - Key gets modified if it contains "\" \ +* [Issue #396](https://github.com/json-c/json-c/issues/396) - Build failure with no threads uClibc toolchain \ +* [Issue #397](https://github.com/json-c/json-c/issues/397) - update json object with key. \ +* [Issue #398](https://github.com/json-c/json-c/issues/398) - Build failed. \ +* [Issue #399](https://github.com/json-c/json-c/issues/399) - Avoid uninitialized variable warnings \ +* [Issue #400](https://github.com/json-c/json-c/issues/400) - How to generate static lib (.a) \ +* [Issue #401](https://github.com/json-c/json-c/issues/401) - Warnings with Valgrind \ +* [Issue #402](https://github.com/json-c/json-c/issues/402) - Add fuzzers from OSS-Fuzz \ +* [Issue #403](https://github.com/json-c/json-c/issues/403) - Segmentation fault when double quotes is used \ +* [Issue #404](https://github.com/json-c/json-c/issues/404) - valgrind: memory leak \ +* [Issue #405](https://github.com/json-c/json-c/issues/405) - Missing API to determine an object is empty \ +* [Issue #406](https://github.com/json-c/json-c/issues/406) - Undefine NDEBUG for tests \ +* [Issue #407](https://github.com/json-c/json-c/issues/407) - json_tokener_parse is crash \ +* [Issue #408](https://github.com/json-c/json-c/issues/408) - bug in array_list_del_idx when array_list_length()==1 \ +* [Issue #410](https://github.com/json-c/json-c/issues/410) - Fixed typos \ +* [Issue #411](https://github.com/json-c/json-c/issues/411) - Crash- signal SIGSEGV, Segmentation fault. ../sysdeps/x86_64/strlen.S: No such file or directory. \ +* [Issue #412](https://github.com/json-c/json-c/issues/412) - json_type changes during inter process communication. \ +* [Issue #413](https://github.com/json-c/json-c/issues/413) - how to read object of type `json_object *` in c++ \ +* [Issue #414](https://github.com/json-c/json-c/issues/414) - [Question] How JSON-c stores the serialized data in memory? \ +* [Issue #415](https://github.com/json-c/json-c/issues/415) - Resolve windows name conflict \ +* [Issue #416](https://github.com/json-c/json-c/issues/416) - segmentation fault in json_tokener_parse \ +* [Issue #417](https://github.com/json-c/json-c/issues/417) - json_tokener_parse json_object_object_get_ex with string value which is json string \ +* [Issue #418](https://github.com/json-c/json-c/issues/418) - json_object_from_* return value documented incorrectly \ +* [Issue #419](https://github.com/json-c/json-c/issues/419) - Suggestion: document (and define) that json_object_put() accepts NULL pointer to object \ +* [Issue #420](https://github.com/json-c/json-c/issues/420) - arraylist: Fixed names of parameters for callback function \ +* [Issue #421](https://github.com/json-c/json-c/issues/421) - install json_object_iterator.h header file \ +* [Issue #422](https://github.com/json-c/json-c/issues/422) - json_object_get_double() does not set errno when there is no valid conversion \ +* [Issue #423](https://github.com/json-c/json-c/issues/423) - memory leak \ +* [Issue #424](https://github.com/json-c/json-c/issues/424) - Parse string contains "\" or "/" errors \ +* [Issue #425](https://github.com/json-c/json-c/issues/425) - what this is? \ +* [Issue #426](https://github.com/json-c/json-c/issues/426) - __deprecated not supported on clang. \ +* [Issue #427](https://github.com/json-c/json-c/issues/427) - CMake: builds involving this target will not be correct \ +* [Issue #430](https://github.com/json-c/json-c/issues/430) - json_object_object_del() and Segmentation fault \ +* [Issue #431](https://github.com/json-c/json-c/issues/431) - cmake: Bump required version \ +* [Issue #432](https://github.com/json-c/json-c/issues/432) - The real CMake support. \ +* [Issue #433](https://github.com/json-c/json-c/issues/433) - The real CMake support. \ +* [Issue #434](https://github.com/json-c/json-c/issues/434) - The real CMake support \ +* [Issue #435](https://github.com/json-c/json-c/issues/435) - json_object_object_del() segmentation fault \ +* [Issue #436](https://github.com/json-c/json-c/issues/436) - Improve pkgconfig setting \ +* [Issue #437](https://github.com/json-c/json-c/issues/437) - Bad link in README.md \ +* [Issue #438](https://github.com/json-c/json-c/issues/438) - Bad link in README.html \ +* [Issue #439](https://github.com/json-c/json-c/issues/439) - reserved identifier violation \ +* [Issue #440](https://github.com/json-c/json-c/issues/440) - Use of angle brackets around file names for include statements \ +* [Issue #441](https://github.com/json-c/json-c/issues/441) - fix c flag loss during cmake building \ +* [Issue #442](https://github.com/json-c/json-c/issues/442) - error in configure file \ +* [Issue #443](https://github.com/json-c/json-c/issues/443) - remove pretty spaces when using pretty tabs \ +* [Issue #444](https://github.com/json-c/json-c/issues/444) - Document refcount of json_tokener_parse_ex return \ +* [Issue #445](https://github.com/json-c/json-c/issues/445) - Add missing "make check" target to cmake config \ +* [Issue #446](https://github.com/json-c/json-c/issues/446) - Forward slashes get escaped \ +* [Issue #448](https://github.com/json-c/json-c/issues/448) - Buffer overflow in json-c \ +* [Issue #449](https://github.com/json-c/json-c/issues/449) - Need of json_type_int64 returned by json_object_get_type() \ +* [Issue #450](https://github.com/json-c/json-c/issues/450) - Allow use json-c cmake as subproject \ +* [Issue #452](https://github.com/json-c/json-c/issues/452) - Update README.md \ +* [Issue #453](https://github.com/json-c/json-c/issues/453) - Fixed misalignment in JSON string due to space after \n being printed... \ +* [Issue #454](https://github.com/json-c/json-c/issues/454) - json_object_private: save 8 bytes in struct json_object in 64-bit arc… \ +* [Issue #455](https://github.com/json-c/json-c/issues/455) - index.html:fix dead link \ +* [Issue #456](https://github.com/json-c/json-c/issues/456) - STYLE.txt:remove executable permissions \ +* [Issue #457](https://github.com/json-c/json-c/issues/457) - .gitignore:add build directory \ +* [Issue #458](https://github.com/json-c/json-c/issues/458) - README.md:fix dead "file.html" link \ +* [Issue #459](https://github.com/json-c/json-c/issues/459) - README.html:fix link to Doxygen docs, remove WIN32 link \ +* [Issue #460](https://github.com/json-c/json-c/issues/460) - No docs for json_object_new_string_len() \ +* [Issue #461](https://github.com/json-c/json-c/issues/461) - json_object.c:set errno in json_object_get_double() \ +* [Issue #462](https://github.com/json-c/json-c/issues/462) - json_object.h:document json_object_new_string_len() \ +* [Issue #463](https://github.com/json-c/json-c/issues/463) - please check newlocale api first argument valuse. \ +* [Issue #465](https://github.com/json-c/json-c/issues/465) - CMakeLists.txt doesn't contain json_object_iterator.h which json.h includes \ +* [Issue #466](https://github.com/json-c/json-c/issues/466) - configure:3610: error: C compiler cannot create executables \ +* [Issue #467](https://github.com/json-c/json-c/issues/467) - Fix compiler warnings \ +* [Issue #468](https://github.com/json-c/json-c/issues/468) - Fix compiler warnings \ +* [Issue #469](https://github.com/json-c/json-c/issues/469) - Build under alpine with pecl install & docker-php-ext-enable? \ +* [Issue #470](https://github.com/json-c/json-c/issues/470) - cfuhash_foreach_remove doesn't upate cfuhash_num_entries \ +* [Issue #472](https://github.com/json-c/json-c/issues/472) - Segmentation fault in json_object_iter_begin \ +* [Issue #473](https://github.com/json-c/json-c/issues/473) - Convert ChangeLog to valid UTF-8 encoding. \ +* [Issue #474](https://github.com/json-c/json-c/issues/474) - Installation directories empty with CMake in pkg-config. \ +* [Issue #475](https://github.com/json-c/json-c/issues/475) - improvement proposal for json_object_object_foreach \ +* [Issue #477](https://github.com/json-c/json-c/issues/477) - Hang/Crash with large strings \ +* [Issue #478](https://github.com/json-c/json-c/issues/478) - json_object_get_string_len returns 0 when value is number \ +* [Issue #479](https://github.com/json-c/json-c/issues/479) - I want to use it in iOS or Android but I can't compile \ +* [Issue #480](https://github.com/json-c/json-c/issues/480) - json-c-0.12.1 failed making from source code \ +* [Issue #481](https://github.com/json-c/json-c/issues/481) - error while loading shared libraries: libjson-c.so.4 \ +* [Issue #482](https://github.com/json-c/json-c/issues/482) - Error "double free or corruption" after free() \ +* [Issue #483](https://github.com/json-c/json-c/issues/483) - compatible with rarely-used Chinese characters in GBK charset \ +* [Issue #485](https://github.com/json-c/json-c/issues/485) - Install CMake module files \ +* [Issue #486](https://github.com/json-c/json-c/issues/486) - In the case of negative double value, it is formatted without including ".0" \ +* [Issue #488](https://github.com/json-c/json-c/issues/488) - Some APIs are not exported when built as shared lib on Win32 \ +* [Issue #489](https://github.com/json-c/json-c/issues/489) - Don't use -Werror by default \ +* [Issue #490](https://github.com/json-c/json-c/issues/490) - do not compile with -Werror by default \ +* [Issue #491](https://github.com/json-c/json-c/issues/491) - build: add option --disable-werror to configure \ +* [Issue #492](https://github.com/json-c/json-c/issues/492) - lack some quick usage in readme \ +* [Issue #494](https://github.com/json-c/json-c/issues/494) - Code generator? \ +* [Issue #495](https://github.com/json-c/json-c/issues/495) - README.md:fix 2 typos \ +* [Issue #496](https://github.com/json-c/json-c/issues/496) - json_pointer.h:suggest minor grammar improvement for pointer doc \ +* [Issue #497](https://github.com/json-c/json-c/issues/497) - add common header for all tests \ +* [Issue #498](https://github.com/json-c/json-c/issues/498) - double_serializer_test fails (with valgrind) \ +* [Issue #499](https://github.com/json-c/json-c/issues/499) - .travis.yml:test on more recent clang and gcc versions \ +* [Issue #500](https://github.com/json-c/json-c/issues/500) - test/Makefile.am:add missing deps for test1 and test2 \ +* [Issue #501](https://github.com/json-c/json-c/issues/501) - undefine NDEBUG for tests \ +* [Issue #502](https://github.com/json-c/json-c/issues/502) - configure error \ +* [Issue #503](https://github.com/json-c/json-c/issues/503) - json-c retuns OK when Invalid json string is passed \ +* [Issue #504](https://github.com/json-c/json-c/issues/504) - json_object_put coredump \ +* [Issue #505](https://github.com/json-c/json-c/issues/505) - Add vcpkg installation instructions \ +* [Issue #506](https://github.com/json-c/json-c/issues/506) - Cannot parse more than one object \ +* [Issue #509](https://github.com/json-c/json-c/issues/509) - Sometimes a double value is not serialized \ +* [Issue #510](https://github.com/json-c/json-c/issues/510) - Bump so-name and improve CMake \ +* [Issue #511](https://github.com/json-c/json-c/issues/511) - Reduce lines for better optimization \ +* [Issue #512](https://github.com/json-c/json-c/issues/512) - Properly append to CMAKE_C_FLAGS string \ +* [Issue #513](https://github.com/json-c/json-c/issues/513) - What does `userdata` means?And what is the case we can use it? \ +* [Issue #514](https://github.com/json-c/json-c/issues/514) - Json c 0.13 \ +* [Issue #515](https://github.com/json-c/json-c/issues/515) - Mies suomesta fixes segfaults and logic errors \ +* [Issue #516](https://github.com/json-c/json-c/issues/516) - Lja slight mods \ +* [Issue #518](https://github.com/json-c/json-c/issues/518) - Escape character "\\003\", get unexpected value \ +* [Issue #519](https://github.com/json-c/json-c/issues/519) - Add test case obj token \ +* [Issue #520](https://github.com/json-c/json-c/issues/520) - Adding type uint64 \ +* [Issue #521](https://github.com/json-c/json-c/issues/521) - build cmake windows 10 \ +* [Issue #522](https://github.com/json-c/json-c/issues/522) - update json_visit testcase \ +* [Issue #523](https://github.com/json-c/json-c/issues/523) - update tsetcase for tokener_c \ +* [Issue #524](https://github.com/json-c/json-c/issues/524) - Increase coverage \ +* [Issue #525](https://github.com/json-c/json-c/issues/525) - update pointer test case \ +* [Issue #526](https://github.com/json-c/json-c/issues/526) - Increased the test coverage of printbuf.c 82% to 92%. \ +* [Issue #527](https://github.com/json-c/json-c/issues/527) - Arraylist testcase \ +* [Issue #528](https://github.com/json-c/json-c/issues/528) - Solve issue #108. Skip \u0000 while parsing. \ +* [Issue #529](https://github.com/json-c/json-c/issues/529) - Increased the test coverage of json_c_version.c 0% to 100%. \ +* [Issue #530](https://github.com/json-c/json-c/issues/530) - validate utf-8 string before parse \ +* [Issue #531](https://github.com/json-c/json-c/issues/531) - validate utf-8 string \ +* [Issue #532](https://github.com/json-c/json-c/issues/532) - json_object_object_get_ex returning the original object \ +* [Issue #533](https://github.com/json-c/json-c/issues/533) - Fix "make check" \ +* [Issue #535](https://github.com/json-c/json-c/issues/535) - short string optimization: excessive array length \ +* [Issue #536](https://github.com/json-c/json-c/issues/536) - add json_object_new_null() \ +* [Issue #538](https://github.com/json-c/json-c/issues/538) - update shortstring and arraylist parameters \ +* [Issue #539](https://github.com/json-c/json-c/issues/539) - double serializes to the old value after set_double \ +* [Issue #541](https://github.com/json-c/json-c/issues/541) - add coveralls auto tool to json-c \ +* [Issue #542](https://github.com/json-c/json-c/issues/542) - add uint64 data to json-c \ +* [Issue #543](https://github.com/json-c/json-c/issues/543) - Readme \ +* [Issue #544](https://github.com/json-c/json-c/issues/544) - Increase distcheck target in cmake \ +* [Issue #545](https://github.com/json-c/json-c/issues/545) - add doc target in cmake \ +* [Issue #546](https://github.com/json-c/json-c/issues/546) - Add uninstall target in cmake \ +* [Issue #547](https://github.com/json-c/json-c/issues/547) - modify json-c default build type, and fix up the assert() errors in t… \ +* [Issue #548](https://github.com/json-c/json-c/issues/548) - Solve some problems about cmake build type (debug/release) \ +* [Issue #549](https://github.com/json-c/json-c/issues/549) - lib installation issues \ +* [Issue #550](https://github.com/json-c/json-c/issues/550) - Format codes with clang-format tool? \ +* [Issue #551](https://github.com/json-c/json-c/issues/551) - Allow hexadecimal number format convention parsing \ +* [Issue #553](https://github.com/json-c/json-c/issues/553) - Fix/clang ubsan \ +* [Issue #554](https://github.com/json-c/json-c/issues/554) - RFC 8259 compatibility mode \ +* [Issue #555](https://github.com/json-c/json-c/issues/555) - Format json-c with clang-format tool \ +* [Issue #556](https://github.com/json-c/json-c/issues/556) - Fixes various Wreturn-type and Wimplicit-fallthrough errors on Mingw-w64 \ +* [Issue #557](https://github.com/json-c/json-c/issues/557) - Add option in CMAKE to not build documentation \ +* [Issue #558](https://github.com/json-c/json-c/issues/558) - modify the doc target message \ +* [Issue #559](https://github.com/json-c/json-c/issues/559) - json_c_visit() not exported on Windows \ +* [Issue #560](https://github.com/json-c/json-c/issues/560) - error: implicit declaration of function '_strtoi64' \ +* [Issue #561](https://github.com/json-c/json-c/issues/561) - add the badge in README.md and test the coveralls \ +* [Issue #562](https://github.com/json-c/json-c/issues/562) - Bugfix and testcases supplements \ +* [Issue #563](https://github.com/json-c/json-c/issues/563) - Changed order of calloc args to match stdlib \ +* [Issue #564](https://github.com/json-c/json-c/issues/564) - Remove autogenerated files \ +* [Issue #565](https://github.com/json-c/json-c/issues/565) - test the CI and ignore this PR \ +* [Issue #566](https://github.com/json-c/json-c/issues/566) - add the json_types.h to Makefile.am \ +* [Issue #567](https://github.com/json-c/json-c/issues/567) - Install json_types.h with autotools build as well. \ +* [Issue #568](https://github.com/json-c/json-c/issues/568) - Adding better support to MinGW \ +* [Issue #569](https://github.com/json-c/json-c/issues/569) - Handling of -Bsymbolic-function in CMakeLists.txt is deficient \ +* [Issue #571](https://github.com/json-c/json-c/issues/571) - CMake: Bump SONAME to 5. \ +* [Issue #572](https://github.com/json-c/json-c/issues/572) - Small fixes to CMakeLists \ +* [Issue #573](https://github.com/json-c/json-c/issues/573) - Fix coveralls submission. \ +* [Issue #574](https://github.com/json-c/json-c/issues/574) - autogen.sh missing from repository \ +* [Issue #575](https://github.com/json-c/json-c/issues/575) - Small cosmetics. \ +* [Issue #576](https://github.com/json-c/json-c/issues/576) - Test coverage for json_c_version. \ +* [Issue #577](https://github.com/json-c/json-c/issues/577) - Be verbose on failing json_c_version test. \ +* [Issue #578](https://github.com/json-c/json-c/issues/578) - CMake: Install pkgconfig file in proper location by default \ +* [Issue #579](https://github.com/json-c/json-c/issues/579) - Enforce strict prototypes. \ +* [Issue #580](https://github.com/json-c/json-c/issues/580) - Fix CMake tests for enforced strict prototypes. \ +* [Issue #581](https://github.com/json-c/json-c/issues/581) - CMakeLists: do not enforce strict prototypes on Windows. \ From 78a0f2ea5da393ee19d4bc5a57679babf22b773f Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Fri, 17 Jul 2020 03:47:28 +0000 Subject: [PATCH 61/94] Remove the obsolete config.h.win32 --- config.h.win32 | 207 ------------------------------------------------- 1 file changed, 207 deletions(-) delete mode 100644 config.h.win32 diff --git a/config.h.win32 b/config.h.win32 deleted file mode 100644 index 130378e..0000000 --- a/config.h.win32 +++ /dev/null @@ -1,207 +0,0 @@ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Enable RDRANR Hardware RNG Hash Seed */ -#undef ENABLE_RDRAND - -/* Define if .gnu.warning accepts long strings. */ -#undef HAS_GNU_WARNING_LONG - -/* Define to 1 if you have the declaration of `INFINITY', and to 0 if you - don't. */ -#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) -#define HAVE_DECL_INFINITY 1 -#endif - -/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. - */ -#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) -#define HAVE_DECL_ISINF 1 -#endif - -/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't. - */ -#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) -#define HAVE_DECL_ISNAN 1 -#endif - -/* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */ -#if (defined(_MSC_VER) && _MSC_VER >= 1800) || defined(__MINGW32__) -#define HAVE_DECL_NAN 1 -#endif - -/* Define to 1 if you have the declaration of `_finite', and to 0 if you - don't. */ -#define HAVE_DECL__FINITE 1 - -/* Define to 1 if you have the declaration of `_isnan', and to 0 if you don't. - */ -#define HAVE_DECL__ISNAN 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DLFCN_H 1 - -/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ -#define HAVE_DOPRNT 1 - -/* Define to 1 if you have the header file. */ -#undef HAVE_ENDIAN_H - -/* Define to 1 if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LIMITS_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_LOCALE_H 1 - -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and - to 0 otherwise. */ -#define HAVE_MALLOC 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `open' function. */ -#define HAVE_OPEN 1 - -/* Define to 1 if your system has a GNU libc compatible `realloc' function, - and to 0 otherwise. */ -#define HAVE_REALLOC 1 - -/* Define to 1 if you have the `setlocale' function. */ -#define HAVE_SETLOCALE 1 - -/* Define to 1 if you have the `snprintf' function. */ -#if defined(__MINGW32__) -#define HAVE_SNPRINTF 1 -#else -#undef HAVE_SNPRINTF -#endif - -/* Define to 1 if you have the header file. */ -#define HAVE_STDARG_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strcasecmp' function. */ -#define HAVE_STRCASECMP 1 - -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRDUP 0 - -/* Define to 1 if you have the `strerror' function. */ -#define HAVE_STRERROR 1 - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strncasecmp' function. */ -#if defined(__MINGW32__) -#define HAVE_STRNCASECMP 1 -#else -#undef HAVE_STRNCASECMP -#endif - -#cmakedefine HAVE_STRTOLL -#cmakedefine strtoll @cmake_strtoll@ -#cmakedefine HAVE_STRTOULL -#cmakedefine strtoull @cmake_strtoull@ - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYSLOG_H - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_CDEFS_H 1 - -/* Define to 1 if you have the header file. */ -#if defined(__MINGW32__) -#define HAVE_SYS_PARAM_H 1 -#else -#undef HAVE_SYS_PARAM_H -#endif - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -#if defined(__MINGW32__) -#define HAVE_UNISTD_H 1 -#else -#undef HAVE_UNISTD_H -#endif - -/* Define to 1 if you have the `vasprintf' function. */ -#if defined(__MINGW32__) -#define HAVE_VASPRINTF 1 -#else -#undef HAVE_VASPRINTF -#endif - -/* Define to 1 if you have the `vprintf' function. */ -#define HAVE_VPRINTF 1 - -/* Define to 1 if you have the `vsnprintf' function. */ -#define HAVE_VSNPRINTF 1 - -/* Define to 1 if you have the `vsyslog' function. */ -#undef HAVE_VSYSLOG - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#undef LT_OBJDIR - -/* Define to 1 if your C compiler doesn't accept -c and -o together. */ -/* #undef NO_MINUS_C_MINUS_O */ - -/* Name of package */ -#define PACKAGE "json-c" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "json-c@googlegroups.com" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "JSON C Library" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "JSON C Library 0.14.99" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "json-c" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "https://github.com/json-c/json-c" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "0.14.99" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -#define VERSION "0.14.99" - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to rpl_malloc if the replacement function should be used. */ -/* #undef malloc */ - -/* Define to rpl_realloc if the replacement function should be used. */ -/* #undef realloc */ - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ From 024e835f4cfb2aacf420d9a330ddbcf5c8dd12d2 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 20 Jul 2020 03:39:01 +0000 Subject: [PATCH 62/94] Update the ChangeLog with recent changes, in preparation for a 0.15 release. --- ChangeLog | 50 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6e46cda..8e1ac53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,14 +4,36 @@ Next Release 0.15 Deprecated and removed features: -------------------------------- -* array_list_new() has been deprecated in favor of array_list_new2() +* Deprecate `array_list_new()` in favor of `array_list_new2()` +* Remove the THIS_FUNCTION_IS_DEPRECATED define. +* Remove config.h.win32 -Other changes --------------- -* Add a json_parse binary, for use in testing changes (not installed). -* Issue #471: always create directories with mode 0755, regardless of umask. -* Added a JSON_TOKENER_ALLOW_TRAILING_CHARS flag to allow multiple objects - to be parsed even when JSON_TOKENER_STRICT is set. +New features +------------ +* Add a `JSON_TOKENER_ALLOW_TRAILING_CHARS` flag to allow multiple objects + to be parsed even when `JSON_TOKENER_STRICT` is set. +* Add `json_object_new_array_ext(int)` and `array_list_new_2(int)` to allow + arrays to be allocated with the exact size needed, when known. +* Add `json_object_array_shrink()` (and `array_list_shrink()`) and use it in + json_tokener to minimize the amount of memory used. +* Add a json_parse binary, for use in testing changes (not installed, but + available in the apps directory). + +Build changes +------------- +* #639/#621 - Add symbol versions to all exported symbols +* #508/#634 - Always enable -fPIC to allow use of the json-c static library in + other libraries +* Build both static and shared libraries at the same time. +* #626 - Restore compatibility with cmake 2.8 +* #471 - Always create directories with mode 0755, regardless of umask. +* #606/#604 - Improve support for OSes like AIX and IBM i, as well as for + MINGW32 and old versions of MSVC +* #451/#617 - Add a DISABLE_THREAD_LOCAL_STORAGE cmake option to disable + the use of thread-local storage. + +Significant changes and bug fixes +--------------------------------- * Split the internal json_object structure into several sub-types, one for each json_type (json_object_object, json_object_string, etc...). This improves memory usage and speed, with the benchmark under @@ -23,9 +45,7 @@ Other changes arrays to the exact number of elements parsed. On bench/ benchmark: 9% faster test time, 39%(max RSS)-50%(peak heap) less memory usage. Add json_object_array_shrink() and array_list_shrink() functions. -* Add json_object_new_array_ext(int) and array_list_new_2(int) to allow - arrays to be allocated with the exact size needed, when known. -* Parsing of surrogate pairs in unicode escapes now properly handles +* #616 - Parsing of surrogate pairs in unicode escapes now properly handles incremental parsing. * Fix incremental parsing of numbers, especially those with exponents, e.g. so parsing "[0", "e+", "-]" now properly returns an error. @@ -34,6 +54,16 @@ Other changes followed by a "-", "." or "e". This makes parsing things like "123-45" behave consistently with things like "123xyz". +Other changes +------------- +* #589 - Detect broken RDRAND during initialization; also, fix segfault + in the CPUID check. +* #592 - Fix integer overflows to prevert out of bounds write on large input. +* Protect against division by zero in linkhash, when creaed with zero size. +* #602 - Fix json_parse_uint64() internal error checking, leaving the retval + untouched in more failure cases. +* #614 - Prevent truncation when custom double formatters insert extra \0's + *** From 1962ba7de30b999a9d08c716fe588b8e562101e3 Mon Sep 17 00:00:00 2001 From: Pascal Cuoq Date: Tue, 21 Jul 2020 17:54:26 +0200 Subject: [PATCH 63/94] Fixes #645 --- json_tokener.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_tokener.c b/json_tokener.c index 63e02a1..6527270 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -430,7 +430,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * { char inf_char = *str; if (!(tok->flags & JSON_TOKENER_STRICT)) - inf_char = tolower((int)*str); + inf_char = tolower((unsigned char)*str); if (inf_char != _json_inf_str[tok->st_pos]) { tok->err = json_tokener_error_parse_unexpected; From 730e3d044f2ac2e44e38bf67ac31c19925428d15 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Wed, 22 Jul 2020 02:25:03 +0000 Subject: [PATCH 64/94] Issue #594 - provide an OVERRIDE_GET_RANDOM_SEED cmake variable to override json_c_get_random_seed() for embedded platforms where time(NULL) doesn't work. Example: mkdir build && cd build cmake -DOVERRIDE_GET_RANDOM_SEED='do { extern uint32_t getMsTicks(void); int ms = getMsTicks() * 433494437; return ms; } while(0)' .. --- CMakeLists.txt | 2 ++ README.md | 1 + cmake/config.h.in | 3 +++ random_seed.c | 3 +++ 4 files changed, 9 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index da0af96..7362a84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,6 +96,8 @@ option(DISABLE_THREAD_LOCAL_STORAGE "Disable using Thread-Local Storage (HAVE_ option(DISABLE_WERROR "Avoid treating compiler warnings as fatal errors." OFF) option(ENABLE_RDRAND "Enable RDRAND Hardware RNG Hash Seed." OFF) option(ENABLE_THREADING "Enable partial threading support." OFF) +option(OVERRIDE_GET_RANDOM_SEED "Override json_c_get_random_seed() with custom code." OFF) + if (UNIX OR MINGW OR CYGWIN) list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) diff --git a/README.md b/README.md index fc128f5..cd66d49 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,7 @@ DISABLE_THREAD_LOCAL_STORAGE | Bool | Disable use of Thread-Local Storage (HAV DISABLE_WERROR | Bool | Disable use of -Werror. ENABLE_RDRAND | Bool | Enable RDRAND Hardware RNG Hash Seed. ENABLE_THREADING | Bool | Enable partial threading support. +OVERRIDE_GET_RANDOM_SEED | String | A block of code to use instead of the default implementation of json_c_get_random_seed(), e.g. on embedded platforms where not even the fallback to time() works. Must be a single line. Pass these options as `-D` on CMake's command-line. diff --git a/cmake/config.h.in b/cmake/config.h.in index 8b31164..547a585 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -2,6 +2,9 @@ /* Enable RDRAND Hardware RNG Hash Seed */ #cmakedefine ENABLE_RDRAND "@ENABLE_RDRAND@" +/* Override json_c_get_random_seed() with custom code */ +#cmakedefine OVERRIDE_GET_RANDOM_SEED @OVERRIDE_GET_RANDOM_SEED@ + /* Enable partial threading support */ #cmakedefine ENABLE_THREADING "@@" diff --git a/random_seed.c b/random_seed.c index 833b1a5..1a15350 100644 --- a/random_seed.c +++ b/random_seed.c @@ -276,6 +276,9 @@ static int get_time_seed(void) int json_c_get_random_seed(void) { +#ifdef OVERRIDE_GET_RANDOM_SEED + OVERRIDE_GET_RANDOM_SEED; +#endif #if defined HAVE_RDRAND && HAVE_RDRAND if (has_rdrand()) return get_rdrand_seed(); From 4a23d3413d48c53dce5d4c881b3fc50354a6d74c Mon Sep 17 00:00:00 2001 From: Marc <34656315+MarcT512@users.noreply.github.com> Date: Thu, 23 Jul 2020 18:19:12 +0100 Subject: [PATCH 65/94] Fix "may be used uninitialized" Release build failure Fixes https://github.com/json-c/json-c/issues/647 --- json_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_object.c b/json_object.c index 2ee39ea..9198257 100644 --- a/json_object.c +++ b/json_object.c @@ -735,7 +735,7 @@ struct json_object *json_object_new_int(int32_t i) int32_t json_object_get_int(const struct json_object *jso) { - int64_t cint64; + int64_t cint64=0; double cdouble; enum json_type o_type; From 870965e1eaa956324f7ed0825fd29ef584c20bc8 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Fri, 24 Jul 2020 03:17:13 +0000 Subject: [PATCH 66/94] Update AUTHORS, add issues_closed_for_0.15.md, tweak the release checklist slightly. --- AUTHORS | 11 +++++ RELEASE_CHECKLIST.txt | 8 ++-- issues_closed_for_0.15.md | 85 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 issues_closed_for_0.15.md diff --git a/AUTHORS b/AUTHORS index fce4dd8..33ff568 100644 --- a/AUTHORS +++ b/AUTHORS @@ -7,8 +7,13 @@ Christopher Head Chris Wolfe C. Watford (christopher.watford@gmail.com) Darjan Krijan +David McCann +dota17 +Eric Haszlakiewicz Eric Hawicz +Gianluigi Tiesi grdowns +hofnarr Ivan Romanov Jaap Keuter janczer @@ -18,13 +23,19 @@ Jonathan Wiens Jose Bollo Keith Holman Liang, Gao +Marc <34656315+MarcT512@users.noreply.github.com> max +Micah Snyder Michael Clark myd7349 +Pascal Cuoq Pierce Lopez Po-Chuan Hsieh Ramiro Polla Rikard Falkeborn Robert Rubasri Kalidas +Simon McVittie +Tobias Stoeckmann +Tudor Brindus Unmanned Player <36690541+unmanned-player@users.noreply.github.com> diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index 20c08fd..a2ba107 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -21,6 +21,10 @@ * Consider re-adding backwards compatible support, through symbol aliases and appropriate entries in json-c.sym * Update the AUTHORS file + + git log -r 31ab57ca..HEAD | grep Author: | sed -e's/Author: //' ; cat AUTHORS ) | sort -u > A1 + mv A1 AUTHORS + * Exclude mentioning changes that have already been included in a point release of the previous release branch. @@ -40,7 +44,7 @@ Start creating the new release: cd distcheck # Note, the build directory *must* be entirely separate from # the source tree for distcheck to work properly. - cmake ../json-c-${release} + cmake -DCMAKE_BUILD_TYPE=Release ../json-c-${release} make distcheck cd .. @@ -55,7 +59,6 @@ Make any fixes/changes *before* branching. Using ${release}: Update the version in json_c_version.h Update the version in CMakeLists.txt (VERSION in the project(...) line) - Update the version in config.h.win32 (several places) Update the set_target_properties() line in CmakeLists.txt to set the shared library version. Generally, unless we're doing a major release, change: @@ -121,7 +124,6 @@ Add new section to ChangeLog for ${release}+1 Use ${release}.99 to indicate a version "newer" than anything on the branch: Update the version in json_c_version.h Update the version in CMakeLists.txt - Update the version in config.h.win32 Update RELEASE_CHECKLIST.txt, set release=${release}+1 diff --git a/issues_closed_for_0.15.md b/issues_closed_for_0.15.md new file mode 100644 index 0000000..8c7f2f6 --- /dev/null +++ b/issues_closed_for_0.15.md @@ -0,0 +1,85 @@ +This list was created with: + +``` +curl "https://api.github.com/search/issues?q=repo%3Ajson-c%2Fjson-c+closed%3A>2020-04-18+created%3A<2020-07-23&sort=created&order=asc&per_page=100&page=1" > issues1.out +jq -r '.items[] | "[" + .title + "](" + .url + ")" | tostring' issues?.out > issues.md +sed -e's,^\[ *\(.*\)\](https://api.github.com/.*/\([0-9].*\)),* [Issue #\2](https://github.com/json-c/json-c/issues/\2) - \1,' -i issues.md +#... manual editing ... + +``` + +---- + +Issues and Pull Requests closed for the 0.15 release +(since commit 31ab57ca, the 0.14 branch point, 2020-04-19) + +* [Issue #428](https://github.com/json-c/json-c/issues/428) - Added new_null() function +* [Issue #429](https://github.com/json-c/json-c/issues/429) - Conflict of interest between JSON_C_TO_STRING_SPACED and JSON_C_TO_STRING_PRETTY +* [Issue #451](https://github.com/json-c/json-c/issues/451) - Add option to disable HAVE___THREAD +* [Issue #471](https://github.com/json-c/json-c/issues/471) - create folders with mode 0755 when building +* [Issue #476](https://github.com/json-c/json-c/issues/476) - Add new function named json_object_new_string_noalloc +* [Issue #484](https://github.com/json-c/json-c/issues/484) - Add support for uint64 +* [Issue #487](https://github.com/json-c/json-c/issues/487) - Any plans to make new release? (0.14) +* [Issue #493](https://github.com/json-c/json-c/issues/493) - Kdopen rename library +* [Issue #507](https://github.com/json-c/json-c/issues/507) - Double value -1.0 converts to integer in json_object_to_json_string() +* [Issue #508](https://github.com/json-c/json-c/issues/508) - Recommend enabling the `-fPIC` compiler flag by default +* [Issue #517](https://github.com/json-c/json-c/issues/517) - Lja mods +* [Issue #534](https://github.com/json-c/json-c/issues/534) - Both json-c and json-glib have json_object_get_type() +* [Issue #584](https://github.com/json-c/json-c/issues/584) - CMake: SOVERSION and the major library VERSION need to be in lockstep. +* [Issue #585](https://github.com/json-c/json-c/issues/585) - CMake: Do not install config.h, as it is not a public header file. +* [Issue #586](https://github.com/json-c/json-c/issues/586) - 10796 Segmentation fault +* [Issue #588](https://github.com/json-c/json-c/issues/588) - Broken RDRAND causes infinite looping +* [Issue #589](https://github.com/json-c/json-c/issues/589) - Detect broken RDRAND during initialization +* [Issue #590](https://github.com/json-c/json-c/issues/590) - Fix segmentation fault in CPUID check +* [Issue #591](https://github.com/json-c/json-c/issues/591) - Update README.md +* [Issue #592](https://github.com/json-c/json-c/issues/592) - Prevent out of boundary write on malicious input +* [Issue #593](https://github.com/json-c/json-c/issues/593) - Building both static and shared libraries +* [Issue #594](https://github.com/json-c/json-c/issues/594) - Some subsequent call of lh_get_hash not working +* [Issue #595](https://github.com/json-c/json-c/issues/595) - Support to build both static and shared libraries +* [Issue #596](https://github.com/json-c/json-c/issues/596) - QA Notice: Package triggers severe warnings +* [Issue #597](https://github.com/json-c/json-c/issues/597) - json_parse demo: fix and use usage() function +* [Issue #598](https://github.com/json-c/json-c/issues/598) - Turning off shared libs causes target duplication or build error +* [Issue #599](https://github.com/json-c/json-c/issues/599) - cannot add more than 11 objects. Is this a known issue? +* [Issue #600](https://github.com/json-c/json-c/issues/600) - Library name conflicts on Windows are back again +* [Issue #601](https://github.com/json-c/json-c/issues/601) - json_tokener_parse() in master sets errno=1 "Operation not permitted" +* [Issue #602](https://github.com/json-c/json-c/issues/602) - fix json_parse_uint64() internal error checking with errno +* [Issue #603](https://github.com/json-c/json-c/issues/603) - Backport of fixes from master branch. +* [Issue #604](https://github.com/json-c/json-c/issues/604) - commit f2e991a3419ee4078e8915e840b1a0d9003b349e breaks cross-compilation with mingw +* [Issue #605](https://github.com/json-c/json-c/issues/605) - Update to 0.15 release +* [Issue #606](https://github.com/json-c/json-c/issues/606) - Improved support for IBM operating systems +* [Issue #607](https://github.com/json-c/json-c/issues/607) - json-c-0.13.x: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ... +* [Issue #608](https://github.com/json-c/json-c/issues/608) - json-c-0.14: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ... +* [Issue #609](https://github.com/json-c/json-c/issues/609) - use unsigned types for sizes in lh_table and entries +* [Issue #610](https://github.com/json-c/json-c/issues/610) - let's not call lh_table_resize with INT_MAX +* [Issue #611](https://github.com/json-c/json-c/issues/611) - json-c-0.12.x: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ... +* [Issue #613](https://github.com/json-c/json-c/issues/613) - json-c-0.10: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ... +* [Issue #614](https://github.com/json-c/json-c/issues/614) - Prevent truncation on custom double formatters. +* [Issue #615](https://github.com/json-c/json-c/issues/615) - New release with security fix +* [Issue #616](https://github.com/json-c/json-c/issues/616) - Parsing fails if UTF-16 low surrogate pair is not in same chunk is the high pair +* [Issue #617](https://github.com/json-c/json-c/issues/617) - Add an option to disable the use of thread-local storage. +* [Issue #618](https://github.com/json-c/json-c/issues/618) - test_deep_copy: Fix assertion value. +* [Issue #619](https://github.com/json-c/json-c/issues/619) - CMake: Fix out-of-tree build for Doxygen documentation. +* [Issue #621](https://github.com/json-c/json-c/issues/621) - json-c and jansson libraries have symbol conflicts +* [Issue #622](https://github.com/json-c/json-c/issues/622) - doc: Move Doxyfile into doc subdir. +* [Issue #623](https://github.com/json-c/json-c/issues/623) - json_tokener_parse : Segmentation fault +* [Issue #626](https://github.com/json-c/json-c/issues/626) - Fixes for cmake 2.8.12 + link issue on AIX 6.1/cc 11.01 +* [Issue #627](https://github.com/json-c/json-c/issues/627) - Compat fixes +* [Issue #628](https://github.com/json-c/json-c/issues/628) - get_cryptgenrandom_seed: compat with old windows + fallback +* [Issue #629](https://github.com/json-c/json-c/issues/629) - [0.12] Remove the Visual Studio project file +* [Issue #630](https://github.com/json-c/json-c/issues/630) - Linking with Windows MINGW not working +* [Issue #632](https://github.com/json-c/json-c/issues/632) - Json object split +* [Issue #633](https://github.com/json-c/json-c/issues/633) - fix issue 616: support the surrogate pair in split file. +* [Issue #634](https://github.com/json-c/json-c/issues/634) - Issue #508: `-fPIC` to link libjson-c.a with libs +* [Issue #635](https://github.com/json-c/json-c/issues/635) - expression has no effect warning in json_tokener.c +* [Issue #636](https://github.com/json-c/json-c/issues/636) - json_object_get_string free str memory +* [Issue #637](https://github.com/json-c/json-c/issues/637) - json_object_put() has 'double free or corruption (out) ' +* [Issue #638](https://github.com/json-c/json-c/issues/638) - json-c/json_object.c:50:2: error: #error Unable to determine size of ssize_t +* [Issue #639](https://github.com/json-c/json-c/issues/639) - build: Add a symbol version to all exported symbols +* [Issue #640](https://github.com/json-c/json-c/issues/640) - Fix build issues with SSIZE_MAX on 64bit Linux +* [Issue #641](https://github.com/json-c/json-c/issues/641) - Formal verification of your test suite +* [Issue #642](https://github.com/json-c/json-c/issues/642) - Please provide more precise informations about when to call json_object_put +* [Issue #643](https://github.com/json-c/json-c/issues/643) - not able to compare with string +* [Issue #644](https://github.com/json-c/json-c/issues/644) - Why src->_userdata not checked before calling strdup? +* [Issue #645](https://github.com/json-c/json-c/issues/645) - Misuse of tolower() in json_tokener.c +* [Issue #646](https://github.com/json-c/json-c/issues/646) - Cast to unsigned char instead of int when calling tolower (Fixes #645) + From de02d09c3223130e93bddd9890afce23744219c0 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 26 Jul 2020 15:26:05 +0000 Subject: [PATCH 67/94] Update the master branch to version 0.15.99 --- CMakeLists.txt | 6 +++--- ChangeLog | 10 +++++++++- RELEASE_CHECKLIST.txt | 15 ++++++++++----- json-c.sym | 5 +++++ json_c_version.h | 4 ++-- 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7362a84..c334316 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,11 +10,11 @@ endif() if (CMAKE_VERSION VERSION_LESS 3.0) project(json-c) set(PROJECT_VERSION_MAJOR "0") - set(PROJECT_VERSION_MINOR "14") + set(PROJECT_VERSION_MINOR "15") set(PROJECT_VERSION_PATCH "99") set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") else() - project(json-c LANGUAGES C VERSION 0.14.99) + project(json-c LANGUAGES C VERSION 0.15.99) endif() # If we've got 3.0 then it's good, let's provide support. Otherwise, leave it be. @@ -417,7 +417,7 @@ add_library(${PROJECT_NAME} ${JSON_C_HEADERS} ) set_target_properties(${PROJECT_NAME} PROPERTIES - VERSION 5.0.0 + VERSION 5.1.0 SOVERSION 5) list(APPEND CMAKE_TARGETS ${PROJECT_NAME}) # If json-c is used as subroject it set to target correct interface -I flags and allow diff --git a/ChangeLog b/ChangeLog index 8e1ac53..b63a443 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,15 @@ -Next Release 0.15 +Next Release 0.16 ===================== +...no changes yet... + + +*** + +0.15 (up to commit 870965e, 2020/07/26) +======================================== + Deprecated and removed features: -------------------------------- * Deprecate `array_list_new()` in favor of `array_list_new2()` diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index a2ba107..2990153 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -20,6 +20,8 @@ * Mention removed features in ChangeLog * Consider re-adding backwards compatible support, through symbol aliases and appropriate entries in json-c.sym + * Be sure any new symbols are listed in json-c.sym as part of + the _new_ release version. * Update the AUTHORS file git log -r 31ab57ca..HEAD | grep Author: | sed -e's/Author: //' ; cat AUTHORS ) | sort -u > A1 @@ -37,7 +39,7 @@ ## Release creation Start creating the new release: - release=0.15 + release=0.16 git clone https://github.com/json-c/json-c json-c-${release} mkdir distcheck @@ -77,9 +79,10 @@ If we're doing a major release (SONAME bump), also bump the version Generate the doxygen documentation: - doxygen + (cd ../distcheck && make doc) + cp -r -p ../distcheck/doc/{html,Doxyfile} doc/. git add -f doc - git commit doc + git commit doc -m "Generate docs for the ${release} release" ------------ @@ -107,7 +110,7 @@ Tag the branch: Go to Amazon S3 service at: https://console.aws.amazon.com/s3/ -Upload the two tarballs in the json-c_releases folder. +Upload the two tarballs in the json-c_releases/releases folder. When uploading, use "Standard" storage class, and make the uploaded files publicly accessible. Logout of Amazon S3, and verify that the files are visible. @@ -127,9 +130,11 @@ Use ${release}.99 to indicate a version "newer" than anything on the branch: Update RELEASE_CHECKLIST.txt, set release=${release}+1 +Add a new empty section to the json-c.sym file, for ${release}+1 + Update the set_target_properties() line in CmakeLists.txt to match the release branch. - git commit -a -m "Update the master branch to version 0.${release}.99" + git commit -a -m "Update the master branch to version ${release}.99" git push ------------ diff --git a/json-c.sym b/json-c.sym index a348204..2dedc6e 100644 --- a/json-c.sym +++ b/json-c.sym @@ -163,3 +163,8 @@ JSONC_0.15 { json_object_array_shrink; json_object_new_array_ext; } JSONC_0.14; + +JSONC_0.16 { +# global: +# ...new symbols here... +} JSONC_0.15; diff --git a/json_c_version.h b/json_c_version.h index 84b6b3e..00de4b3 100644 --- a/json_c_version.h +++ b/json_c_version.h @@ -17,11 +17,11 @@ extern "C" { #endif #define JSON_C_MAJOR_VERSION 0 -#define JSON_C_MINOR_VERSION 14 +#define JSON_C_MINOR_VERSION 15 #define JSON_C_MICRO_VERSION 99 #define JSON_C_VERSION_NUM \ ((JSON_C_MAJOR_VERSION << 16) | (JSON_C_MINOR_VERSION << 8) | JSON_C_MICRO_VERSION) -#define JSON_C_VERSION "0.14.99" +#define JSON_C_VERSION "0.15.99" #ifndef JSON_EXPORT #if defined(_MSC_VER) From 47189b5ff182c233e4f93a7c3c22037a1252f047 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sun, 26 Jul 2020 15:51:07 +0000 Subject: [PATCH 68/94] Include updating the json-c-current-releaes gh-pages symlink as part of the release process. --- RELEASE_CHECKLIST.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index 2990153..da5d8d7 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -150,6 +150,8 @@ Update the gh-pages branch with new docs: mkdir json-c-${release} cp -R ../json-c-${release}/doc json-c-${release}/. git add json-c-${release} + rm json-c-current-release + ln -s json-c-${release} json-c-current-release git commit -a -m "Add the ${release} docs." vi index.html From 55bf2d365de8157968d26c3bd0847776ffb2af29 Mon Sep 17 00:00:00 2001 From: Jakov Smolic Date: Mon, 27 Jul 2020 10:30:08 +0200 Subject: [PATCH 69/94] README: fix spelling errors Signed-off-by: Jakov Smolic --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index cd66d49..d2373fc 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Home page for json-c: https://github.com/json-c/json-c/wiki - `gcc`, `clang`, or another C compiler - - cmake>=2.8, >=3.16 recommended + - `cmake>=2.8`, `>=3.16` recommended To generate docs you'll also need: - `doxygen>=1.8.13` @@ -80,7 +80,7 @@ $ make install ### Generating documentation with Doxygen: -The libray documentation can be generated directly from the source codes using Doxygen tool: +The library documentation can be generated directly from the source code using Doxygen tool: ```sh # in build directory @@ -241,7 +241,7 @@ following more specific header files: objects from a json-c object tree. * json_object_iterator.h - Methods for iterating over single json_object instances. (See also `json_object_object_foreach()` in json_object.h) * json_visit.h - Methods for walking a tree of json-c objects. -* json_util.h - Miscelleanous utility functions. +* json_util.h - Miscellaneous utility functions. For a full list of headers see [files.html](http://json-c.github.io/json-c/json-c-current-release/doc/html/files.html) @@ -251,7 +251,7 @@ json_tokener (i.e. `json_tokener_parse_ex()`), or by creating (with `json_object_new_object()`, `json_object_new_int()`, etc...) and adding (with `json_object_object_add()`, `json_object_array_add()`, etc...) them individually. -Typically, every object in the tree will have one reference, from it's parent. +Typically, every object in the tree will have one reference, from its parent. When you are done with the tree of objects, you call json_object_put() on just the root object to free it, which recurses down through any child objects calling json_object_put() on each one of those in turn. @@ -266,7 +266,7 @@ the parent being freed or it being removed from its parent When parsing text, the json_tokener object is independent from the json_object that it returns. It can be allocated (`json_tokener_new()`) -used ones or multiple times (`json_tokener_parse_ex()`, and +used one or multiple times (`json_tokener_parse_ex()`, and freed (`json_tokener_free()`) while the json_object objects live on. A json_object tree can be serialized back into a string with From 002411293d0271424827d970cc34d39968559137 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Tue, 28 Jul 2020 03:52:22 +0000 Subject: [PATCH 70/94] Issue #649: Drop the generated doc/Doxyfile when creating a release. --- RELEASE_CHECKLIST.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index da5d8d7..8e70617 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -81,6 +81,7 @@ Generate the doxygen documentation: (cd ../distcheck && make doc) cp -r -p ../distcheck/doc/{html,Doxyfile} doc/. + rm doc/Doxyfile # Remove generated file w/ hardcoded paths git add -f doc git commit doc -m "Generate docs for the ${release} release" From 6cf48477960b96aedca2c87cf7bb53861ceeecd2 Mon Sep 17 00:00:00 2001 From: Alan Coopersmith Date: Thu, 30 Jul 2020 16:13:04 -0700 Subject: [PATCH 71/94] Use getrandom() if available in json_c_get_random_seed Lower overhead than opening & reading from /dev/urandom, and works in chroots and other situtations where /dev/urandom is not available. Falls back to existing methods when kernel doesn't support the syscall. --- CMakeLists.txt | 4 ++++ cmake/config.h.in | 6 ++++++ random_seed.c | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index c334316..2333d08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,6 +144,7 @@ check_include_file(stdint.h HAVE_STDINT_H) check_include_file(stdlib.h HAVE_STDLIB_H) check_include_file(sys/cdefs.h HAVE_SYS_CDEFS_H) check_include_file(sys/param.h HAVE_SYS_PARAM_H) +check_include_file(sys/random.h HAVE_SYS_RANDOM_H) check_include_file(sys/stat.h HAVE_SYS_STAT_H) check_include_file(xlocale.h HAVE_XLOCALE_H) @@ -190,6 +191,9 @@ endif() if (HAVE_SYSLOG_H) check_symbol_exists(vsyslog "syslog.h" HAVE_VSYSLOG) endif() +if (HAVE_SYS_RANDOM_H) + check_symbol_exists(getrandom "sys/random.h" HAVE_GETRANDOM) +endif() if (HAVE_SYS_RESOURCE_H) check_symbol_exists(getrusage "sys/resource.h" HAVE_GETRUSAGE) endif() diff --git a/cmake/config.h.in b/cmake/config.h.in index 547a585..9e097cb 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -56,6 +56,9 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_PARAM_H @HAVE_SYS_PARAM_H@ +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_RANDOM_H + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_RESOURCE_H @@ -140,6 +143,9 @@ /* Define to 1 if you have the `vsyslog' function. */ #cmakedefine HAVE_VSYSLOG @HAVE_VSYSLOG@ +/* Define if you have the `getrandom' function. */ +#cmakedefine HAVE_GETRANDOM + /* Define if you have the `getrusage' function. */ #cmakedefine HAVE_GETRUSAGE diff --git a/random_seed.c b/random_seed.c index 1a15350..17727c6 100644 --- a/random_seed.c +++ b/random_seed.c @@ -155,6 +155,40 @@ retry: #endif /* defined ENABLE_RDRAND */ +#ifdef HAVE_GETRANDOM + +#include +#ifdef HAVE_SYS_RANDOM_H +#include +#endif + +static int get_getrandom_seed(void) +{ + DEBUG_SEED("get_dev_random_seed"); + + int r; + ssize_t ret; + + do { + ret = getrandom(&r, sizeof(r), 0); + } while ((ret == -1) && (errno == EINTR)); + + if (ret == -1) + { + if (errno == ENOSYS) /* syscall not available in kernel */ + return -1; + + fprintf(stderr, "error from getrandom(): %s", strerror(errno)); + exit(1); + } + + if (ret != sizeof(r)) + return -1; + + return r; +} +#endif /* defined HAVE_GETRANDOM */ + /* has_dev_urandom */ #if defined(__APPLE__) || defined(__unix__) || defined(__linux__) @@ -283,6 +317,13 @@ int json_c_get_random_seed(void) if (has_rdrand()) return get_rdrand_seed(); #endif +#ifdef HAVE_GETRANDOM + { + int seed = get_getrandom_seed(); + if (seed != -1) + return seed; + } +#endif #if defined HAVE_DEV_RANDOM && HAVE_DEV_RANDOM if (has_dev_urandom()) return get_dev_random_seed(); From 46eea845544bb89e8298a25ccc1d3ffdf4967e38 Mon Sep 17 00:00:00 2001 From: Chris Lamb Date: Sat, 1 Aug 2020 11:26:53 +0100 Subject: [PATCH 72/94] Make the documentation build reproducibly Whilst working on the Reproducible Builds effort [0] I noticed that json-c could not be built reproducibly. This is because it used the full, absolute path name as an (sanitised) input to a filename, resulting in some binary package containing, for example: /usr/share/doc/libjson-c-dev/html/md__build_1st_json-c-0_815_issues_closed_for_0_813.html ^^^^^^^^^^^^^^^^^^^^^^ or /usr/share/doc/libjson-c-dev/html/md__build_2_json-c-0_815_2nd_issues_closed_for_0_813.html ^^^^^^^^^^^^^^^^^^^^^^^^ These differing values are based on the path in which json-c is built. This was originally filed in Debian as #966657 [1]. [0] https://reproducible-builds.org/ [1] https://bugs.debian.org/966657 --- doc/Doxyfile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 1d489a7..e411023 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -152,7 +152,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which From 4e9e44e5258dee7654f74948b0dd5da39c28beec Mon Sep 17 00:00:00 2001 From: Marc <34656315+MarcT512@users.noreply.github.com> Date: Fri, 7 Aug 2020 10:49:45 +0100 Subject: [PATCH 73/94] Fix read past end of buffer Resolves https://github.com/json-c/json-c/issues/654 --- apps/json_parse.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/json_parse.c b/apps/json_parse.c index bba4622..72b31a8 100644 --- a/apps/json_parse.c +++ b/apps/json_parse.c @@ -82,7 +82,8 @@ static int parseit(int fd, int (*callback)(struct json_object *)) int parse_end = json_tokener_get_parse_end(tok); if (obj == NULL && jerr != json_tokener_continue) { - char *aterr = &buf[start_pos + parse_end]; + char *aterr = (start_pos + parse_end < sizeof(buf)) ? + &buf[start_pos + parse_end] : ""; fflush(stdout); int fail_offset = total_read - ret + start_pos + parse_end; fprintf(stderr, "Failed at offset %d: %s %c\n", fail_offset, From 0ffb38440935b2c71fa4851d2f44f2d120f24735 Mon Sep 17 00:00:00 2001 From: Aram Poghosyan Date: Fri, 14 Aug 2020 11:45:33 +0400 Subject: [PATCH 74/94] Fixed warnings --- json_object.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json_object.c b/json_object.c index 9198257..6c572a8 100644 --- a/json_object.c +++ b/json_object.c @@ -1724,7 +1724,7 @@ static int json_object_deep_copy_recursive(struct json_object *src, struct json_ /* This handles the `json_type_null` case */ if (!iter.val) jso = NULL; - else if (json_object_deep_copy_recursive(iter.val, src, iter.key, -1, &jso, + else if (json_object_deep_copy_recursive(iter.val, src, iter.key, UINT_MAX, &jso, shallow_copy) < 0) { json_object_put(jso); @@ -1789,7 +1789,7 @@ int json_object_deep_copy(struct json_object *src, struct json_object **dst, if (shallow_copy == NULL) shallow_copy = json_c_shallow_copy_default; - rc = json_object_deep_copy_recursive(src, NULL, NULL, -1, dst, shallow_copy); + rc = json_object_deep_copy_recursive(src, NULL, NULL, UINT_MAX, dst, shallow_copy); if (rc < 0) { json_object_put(*dst); From f052e42f56eae6b8a5b3833731e1d85e054fa09e Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Sat, 15 Aug 2020 15:41:41 +0200 Subject: [PATCH 75/94] Use GRND_NONBLOCK with getrandom. The json-c library is used in cryptsetup for LUKS2 header information. Since cryptsetup can be called very early during boot, the developers avoid getrandom() calls in their own code base for now. [1] Introducing a blocking getrandom() call in json-c therefore introduces this issue for cryptsetup as well. Even though cryptsetup issues do not have to be json-c issues, here is my proposal: Let's use a non-blocking call, falling back to other sources if the call would block. Since getrandom() accesses urandom, it must mean that we are in an early boot phase -- otherwise the call would not block according to its manual page. As stated in manual page of random(4), accessing /dev/urandom won't block but return weak random numbers, therefore this fallback would work for json-c. While at it, fixed the debug message. [1] https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/47 which references to https://lwn.net/Articles/800509/ --- random_seed.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/random_seed.c b/random_seed.c index 17727c6..c428da9 100644 --- a/random_seed.c +++ b/random_seed.c @@ -164,19 +164,21 @@ retry: static int get_getrandom_seed(void) { - DEBUG_SEED("get_dev_random_seed"); + DEBUG_SEED("get_getrandom_seed"); int r; ssize_t ret; do { - ret = getrandom(&r, sizeof(r), 0); + ret = getrandom(&r, sizeof(r), GRND_NONBLOCK); } while ((ret == -1) && (errno == EINTR)); if (ret == -1) { if (errno == ENOSYS) /* syscall not available in kernel */ return -1; + if (errno == EAGAIN) /* entropy not yet initialized */ + return -1; fprintf(stderr, "error from getrandom(): %s", strerror(errno)); exit(1); From 2b439ea59857747067e8272011ad67303e0d4cf1 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 17 Aug 2020 14:55:54 +0000 Subject: [PATCH 76/94] Fix json_object_get_boolean() doc for the object and array cases (always returns 0), and add those cases to the test_cast test. See also issue #658. --- json_object.h | 5 +++-- tests/test_cast.c | 10 ++++++++++ tests/test_cast.expected | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/json_object.h b/json_object.h index a54541c..036be64 100644 --- a/json_object.h +++ b/json_object.h @@ -656,8 +656,9 @@ JSON_EXPORT struct json_object *json_object_new_boolean(json_bool b); * The type is coerced to a json_bool if the passed object is not a json_bool. * integer and double objects will return 0 if there value is zero * or 1 otherwise. If the passed object is a string it will return - * 1 if it has a non zero length. If any other object type is passed - * 1 will be returned if the object is not NULL. + * 1 if it has a non zero length. + * If any other object type is passed 0 will be returned, even non-empty + * json_type_array and json_type_object objects. * * @param obj the json_object instance * @returns a json_bool diff --git a/tests/test_cast.c b/tests/test_cast.c index fb63e0d..fc769f5 100644 --- a/tests/test_cast.c +++ b/tests/test_cast.c @@ -28,6 +28,11 @@ int main(int argc, char **argv) \"int64_number\": 2147483649,\n\ \"negative_number\": -321321321,\n\ \"a_null\": null,\n\ + \"empty_array\": [],\n\ + \"nonempty_array\": [ 123 ],\n\ + \"array_with_zero\": [ 0 ],\n\ + \"empty_object\": {},\n\ + \"nonempty_object\": { \"a\": 123 },\n\ }"; /* Note: 2147483649 = INT_MAX + 2 */ /* Note: 9223372036854775809 = INT64_MAX + 2 */ @@ -49,6 +54,11 @@ int main(int argc, char **argv) getit(new_obj, "int64_number"); getit(new_obj, "negative_number"); getit(new_obj, "a_null"); + getit(new_obj, "empty_array"); + getit(new_obj, "nonempty_array"); + getit(new_obj, "array_with_zero"); + getit(new_obj, "empty_object"); + getit(new_obj, "nonempty_object"); // Now check the behaviour of the json_object_is_type() function. printf("\n================================\n"); diff --git a/tests/test_cast.expected b/tests/test_cast.expected index 347d540..6a19de9 100644 --- a/tests/test_cast.expected +++ b/tests/test_cast.expected @@ -7,6 +7,11 @@ Parsed input: { "int64_number": 2147483649, "negative_number": -321321321, "a_null": null, + "empty_array": [], + "nonempty_array": [ 123 ], + "array_with_zero": [ 0 ], + "empty_object": {}, + "nonempty_object": { "a": 123 }, } Result is not NULL new_obj.string_of_digits json_object_get_type()=string @@ -57,6 +62,36 @@ new_obj.a_null json_object_get_int64()=0 new_obj.a_null json_object_get_uint64()=0 new_obj.a_null json_object_get_boolean()=0 new_obj.a_null json_object_get_double()=0.000000 +new_obj.empty_array json_object_get_type()=array +new_obj.empty_array json_object_get_int()=0 +new_obj.empty_array json_object_get_int64()=0 +new_obj.empty_array json_object_get_uint64()=0 +new_obj.empty_array json_object_get_boolean()=0 +new_obj.empty_array json_object_get_double()=0.000000 +new_obj.nonempty_array json_object_get_type()=array +new_obj.nonempty_array json_object_get_int()=0 +new_obj.nonempty_array json_object_get_int64()=0 +new_obj.nonempty_array json_object_get_uint64()=0 +new_obj.nonempty_array json_object_get_boolean()=0 +new_obj.nonempty_array json_object_get_double()=0.000000 +new_obj.array_with_zero json_object_get_type()=array +new_obj.array_with_zero json_object_get_int()=0 +new_obj.array_with_zero json_object_get_int64()=0 +new_obj.array_with_zero json_object_get_uint64()=0 +new_obj.array_with_zero json_object_get_boolean()=0 +new_obj.array_with_zero json_object_get_double()=0.000000 +new_obj.empty_object json_object_get_type()=object +new_obj.empty_object json_object_get_int()=0 +new_obj.empty_object json_object_get_int64()=0 +new_obj.empty_object json_object_get_uint64()=0 +new_obj.empty_object json_object_get_boolean()=0 +new_obj.empty_object json_object_get_double()=0.000000 +new_obj.nonempty_object json_object_get_type()=object +new_obj.nonempty_object json_object_get_int()=0 +new_obj.nonempty_object json_object_get_int64()=0 +new_obj.nonempty_object json_object_get_uint64()=0 +new_obj.nonempty_object json_object_get_boolean()=0 +new_obj.nonempty_object json_object_get_double()=0.000000 ================================ json_object_is_type: null,boolean,double,int,object,array,string From 4298431150df9a83390a14006217c230e684994b Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Sat, 22 Aug 2020 11:35:50 +0200 Subject: [PATCH 77/94] Properly format errnos in _json_c_strerror The function _json_c_strerror does not properly format unknown errnos. The int to ascii loop ignores the leading digit if the number can be divided by 10 and if an errno has been formatted, shorter errnos would not properly terminate the newly created string, showing the ending numbers of the previous output. A test case has been added to show these effects. Since this function has been introduced for tests, the effect of this on real life code is basically non-existing. First an environment variable has to be set to activate this strerror code and second an unknown errno would have to be encountered. --- strerror_override.c | 3 ++- tests/CMakeLists.txt | 3 ++- tests/test_strerror.c | 11 +++++++++++ tests/test_strerror.expected | 2 ++ tests/test_strerror.test | 1 + 5 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 tests/test_strerror.c create mode 100644 tests/test_strerror.expected create mode 120000 tests/test_strerror.test diff --git a/strerror_override.c b/strerror_override.c index 7a262f7..a3dd377 100644 --- a/strerror_override.c +++ b/strerror_override.c @@ -94,7 +94,7 @@ char *_json_c_strerror(int errno_in) } // It's not one of the known errno values, return the numeric value. - for (ii = 0; errno_in > 10; errno_in /= 10, ii++) + for (ii = 0; errno_in >= 10; errno_in /= 10, ii++) { digbuf[ii] = "0123456789"[(errno_in % 10)]; } @@ -105,5 +105,6 @@ char *_json_c_strerror(int errno_in) { errno_buf[start_idx] = digbuf[ii]; } + errno_buf[start_idx] = '\0'; return errno_buf; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 125f615..0c5c26e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,12 +32,13 @@ foreach(TESTNAME test_printbuf test_set_serializer test_set_value + test_strerror test_util_file test_visit test_object_iterator) add_executable(${TESTNAME} ${TESTNAME}.c) -if(${TESTNAME} STREQUAL test_util_file) +if(${TESTNAME} STREQUAL test_strerror OR ${TESTNAME} STREQUAL test_util_file) # For output consistency, we need _json_c_strerror() in some tests: target_sources(${TESTNAME} PRIVATE ../strerror_override.c) endif() diff --git a/tests/test_strerror.c b/tests/test_strerror.c new file mode 100644 index 0000000..1780564 --- /dev/null +++ b/tests/test_strerror.c @@ -0,0 +1,11 @@ +#include "strerror_override.h" +#include "strerror_override_private.h" + +#include + +int main(int argc, char **argv) +{ + puts(strerror(10000)); + puts(strerror(999)); + return 0; +} diff --git a/tests/test_strerror.expected b/tests/test_strerror.expected new file mode 100644 index 0000000..b6b3bb6 --- /dev/null +++ b/tests/test_strerror.expected @@ -0,0 +1,2 @@ +ERRNO=10000 +ERRNO=999 diff --git a/tests/test_strerror.test b/tests/test_strerror.test new file mode 120000 index 0000000..58a13f4 --- /dev/null +++ b/tests/test_strerror.test @@ -0,0 +1 @@ +test_basic.test \ No newline at end of file From 583911a66c5b1103e7c98e59ef165631c0cbf290 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Sat, 22 Aug 2020 13:07:45 +0200 Subject: [PATCH 78/94] Aligned comment in _json_object_new_string The comment only aligns correctly if tab size is 4. Replaced spaces with tabs to stay in sync with style of other lines. --- json_object.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/json_object.c b/json_object.c index 6c572a8..f8d14d5 100644 --- a/json_object.c +++ b/json_object.c @@ -1254,17 +1254,17 @@ static struct json_object *_json_object_new_string(const char *s, const size_t l struct json_object_string *jso; /* - * Structures Actual memory layout - * ------------------- -------------------- + * Structures Actual memory layout + * ------------------- -------------------- * [json_object_string [json_object_string * [json_object] [json_object] - * ...other fields... ...other fields... + * ...other fields... ...other fields... * c_string] len - * bytes + * bytes * of * string * data - * \0] + * \0] */ if (len > (SSIZE_T_MAX - (sizeof(*jso) - sizeof(jso->c_string)) - 1)) return NULL; From e50154f615cbd2a14857a6f68462e3a699be42d8 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Sat, 22 Aug 2020 13:09:11 +0200 Subject: [PATCH 79/94] Cap string length at INT_MAX. Several issues occur if a string is longer than INT_MAX: - The function json_object_get_string_len returns the length of a string as int. If the string is longer than INT_MAX, the result would be negative. - That in turn would lead to possible out of boundary access when comparing these strings with memcmp and the returned length as done in json_object_equal. - If json_escape_str is called with such strings, out of boundary accesses can occur due to internal int handling (also fixed). - The string cannot be printed out due to printbuffer limits at INT_MAX (which is still true after this commit). Such huge strings can only be inserted through API calls at this point because input files are capped at INT_MAX anyway. Due to huge amount of RAM needed to reproduce these issues I have not added test cases. --- json_object.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/json_object.c b/json_object.c index f8d14d5..b42026b 100644 --- a/json_object.c +++ b/json_object.c @@ -214,7 +214,7 @@ static inline const char *get_string_component(const struct json_object *jso) static int json_escape_str(struct printbuf *pb, const char *str, size_t len, int flags) { - int pos = 0, start_offset = 0; + size_t pos = 0, start_offset = 0; unsigned char c; while (len--) { @@ -1329,9 +1329,10 @@ static int _json_object_set_string_len(json_object *jso, const char *s, size_t l if (jso == NULL || jso->o_type != json_type_string) return 0; - if (len >= SSIZE_T_MAX - 1) + if (len >= INT_MAX - 1) // jso->len is a signed ssize_t, so it can't hold the - // full size_t range. + // full size_t range. json_object_get_string_len returns + // length as int, cap length at INT_MAX. return 0; dstbuf = get_string_component_mutable(jso); From bcb6d7d3474b687718cbaee7bf203db4456fb6b3 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Sat, 22 Aug 2020 13:18:10 +0200 Subject: [PATCH 80/94] Handle allocation failure in json_tokener_new_ex The allocation of printbuf_new might fail. Return NULL to indicate tis error to the caller. Otherwise later usage of the returned tokener would lead to null pointer dereference. --- json_tokener.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/json_tokener.c b/json_tokener.c index 6527270..aad463a 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -134,6 +134,12 @@ struct json_tokener *json_tokener_new_ex(int depth) return NULL; } tok->pb = printbuf_new(); + if (!tok->pb) + { + free(tok); + free(tok->stack); + return NULL; + } tok->max_depth = depth; json_tokener_reset(tok); return tok; From df62119b7f11dbd97715668a6311410f67bea3c9 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Sat, 22 Aug 2020 13:23:23 +0200 Subject: [PATCH 81/94] Prevent signed overflow in get_time_seed Casting time(2) return value to int and multiplying the result with such a constant will definitely lead to a signed overflow by this day. Since signed overflows are undefined behaviour in C, avoid this. Casting to unsigned is more than enough since the upper bits of a 64 bit time_t value will be removed with the int conversion anyway. --- random_seed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/random_seed.c b/random_seed.c index c428da9..b4c0afd 100644 --- a/random_seed.c +++ b/random_seed.c @@ -305,7 +305,7 @@ static int get_time_seed(void) { DEBUG_SEED("get_time_seed"); - return (int)time(NULL) * 433494437; + return (unsigned)time(NULL) * 433494437; } /* json_c_get_random_seed */ From 369e8477d25132e9eeefb89ae1dacb3c4a738652 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Sat, 22 Aug 2020 12:06:15 +0200 Subject: [PATCH 82/94] Validate size arguments in arraylist functions. The array_list_new2 function, which is externally reachable through json_object_new_array_ext, does not check if specified initial size actually fits into memory on 32 bit architectures. It also allows negative values, which could lead to an overflow on these architectures as well. I have added test cases for these situations. While at it, also protect array_list_shrink against too large empty_slots argument. No test added because it takes a huge length value, therefore a lot of items within the array, to overflow the calculation. In theory this affects 64 bit sytems as well, but since the arraylist API is not supposed to be used by external applications according to its header file, the call is protected due to int limitation of json_object_array_shrink. --- arraylist.c | 4 ++++ tests/test1.c | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/arraylist.c b/arraylist.c index c21b8e1..d8e12d1 100644 --- a/arraylist.c +++ b/arraylist.c @@ -45,6 +45,8 @@ struct array_list *array_list_new2(array_list_free_fn *free_fn, int initial_size { struct array_list *arr; + if (initial_size < 0 || (size_t)initial_size >= SIZE_T_MAX / sizeof(void *)) + return NULL; arr = (struct array_list *)malloc(sizeof(struct array_list)); if (!arr) return NULL; @@ -106,6 +108,8 @@ int array_list_shrink(struct array_list *arr, size_t empty_slots) void *t; size_t new_size; + if (empty_slots >= SIZE_T_MAX / sizeof(void *) - arr->length) + return -1; new_size = arr->length + empty_slots; if (new_size == arr->size) return 0; diff --git a/tests/test1.c b/tests/test1.c index 6682120..7e41610 100644 --- a/tests/test1.c +++ b/tests/test1.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -307,6 +308,27 @@ int main(int argc, char **argv) } printf("my_object.to_string()=%s\n", json_object_to_json_string(my_object)); + json_object_put(my_array); + my_array = json_object_new_array_ext(INT_MIN + 1); + if (my_array != NULL) + { + printf("ERROR: able to allocate an array of negative size!\n"); + fflush(stdout); + json_object_put(my_array); + my_array = NULL; + } + +#if SIZEOF_SIZE_T == SIZEOF_INT + my_array = json_object_new_array_ext(INT_MAX / 2 + 2); + if (my_array != NULL) + { + printf("ERROR: able to allocate an array of insufficient size!\n"); + fflush(stdout); + json_object_put(my_array); + my_array = NULL; + } +#endif + json_object_put(my_string); json_object_put(my_int); json_object_put(my_null); From 7af593c140523efa04e863f3772f0632c7ffcde3 Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Fri, 11 Sep 2020 21:09:40 +0200 Subject: [PATCH 83/94] Fixed test1 regression. SIZEOF_SIZE_T might be only defined in config.h. Include config.h for these systems to pass tests which are only supposed to be run on 32 bit systems. Fixes issue #666. --- tests/test1.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test1.c b/tests/test1.c index 7e41610..4d29601 100644 --- a/tests/test1.c +++ b/tests/test1.c @@ -5,6 +5,8 @@ #include #include +#include "config.h" + #include "json.h" #include "parse_flags.h" From 0fd3b7d316bcfbca2bac875eea396fbc9cf08b33 Mon Sep 17 00:00:00 2001 From: Pierce Lopez Date: Wed, 7 Oct 2020 01:22:30 -0400 Subject: [PATCH 84/94] random_seed: on error, continue to next method instead of exiting the process --- random_seed.c | 71 ++++++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/random_seed.c b/random_seed.c index b4c0afd..ff5338f 100644 --- a/random_seed.c +++ b/random_seed.c @@ -162,15 +162,14 @@ retry: #include #endif -static int get_getrandom_seed(void) +static int get_getrandom_seed(int *seed) { DEBUG_SEED("get_getrandom_seed"); - int r; ssize_t ret; do { - ret = getrandom(&r, sizeof(r), GRND_NONBLOCK); + ret = getrandom(seed, sizeof(*seed), GRND_NONBLOCK); } while ((ret == -1) && (errno == EINTR)); if (ret == -1) @@ -181,17 +180,17 @@ static int get_getrandom_seed(void) return -1; fprintf(stderr, "error from getrandom(): %s", strerror(errno)); - exit(1); + return -1; } - if (ret != sizeof(r)) + if (ret != sizeof(*seed)) return -1; - return r; + return 0; } #endif /* defined HAVE_GETRANDOM */ -/* has_dev_urandom */ +/* get_dev_random_seed */ #if defined(__APPLE__) || defined(__unix__) || defined(__linux__) @@ -207,39 +206,32 @@ static int get_getrandom_seed(void) static const char *dev_random_file = "/dev/urandom"; -static int has_dev_urandom(void) -{ - struct stat buf; - if (stat(dev_random_file, &buf)) - { - return 0; - } - return ((buf.st_mode & S_IFCHR) != 0); -} - -/* get_dev_random_seed */ - -static int get_dev_random_seed(void) +static int get_dev_random_seed(int *seed) { DEBUG_SEED("get_dev_random_seed"); + struct stat buf; + if (stat(dev_random_file, &buf)) + return -1; + if ((buf.st_mode & S_IFCHR) == 0) + return -1; + int fd = open(dev_random_file, O_RDONLY); if (fd < 0) { fprintf(stderr, "error opening %s: %s", dev_random_file, strerror(errno)); - exit(1); + return -1; } - int r; - ssize_t nread = read(fd, &r, sizeof(r)); - if (nread != sizeof(r)) + ssize_t nread = read(fd, seed, sizeof(*seed)); + if (nread != sizeof(*seed)) { fprintf(stderr, "error short read %s: %s", dev_random_file, strerror(errno)); - exit(1); + return -1; } close(fd); - return r; + return 0; } #endif @@ -262,9 +254,7 @@ static int get_dev_random_seed(void) #pragma comment(lib, "advapi32.lib") #endif -static int get_time_seed(void); - -static int get_cryptgenrandom_seed(void) +static int get_cryptgenrandom_seed(int *seed) { HCRYPTPROV hProvider = 0; DWORD dwFlags = CRYPT_VERIFYCONTEXT; @@ -279,20 +269,20 @@ static int get_cryptgenrandom_seed(void) if (!CryptAcquireContextA(&hProvider, 0, 0, PROV_RSA_FULL, dwFlags)) { fprintf(stderr, "error CryptAcquireContextA 0x%08lx", GetLastError()); - r = get_time_seed(); + return -1; } else { - BOOL ret = CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r); + BOOL ret = CryptGenRandom(hProvider, sizeof(*seed), (BYTE*)seed); CryptReleaseContext(hProvider, 0); if (!ret) { fprintf(stderr, "error CryptGenRandom 0x%08lx", GetLastError()); - r = get_time_seed(); + return -1; } } - return r; + return 0; } #endif @@ -312,6 +302,7 @@ static int get_time_seed(void) int json_c_get_random_seed(void) { + int seed; #ifdef OVERRIDE_GET_RANDOM_SEED OVERRIDE_GET_RANDOM_SEED; #endif @@ -320,18 +311,16 @@ int json_c_get_random_seed(void) return get_rdrand_seed(); #endif #ifdef HAVE_GETRANDOM - { - int seed = get_getrandom_seed(); - if (seed != -1) - return seed; - } + if (get_getrandom_seed(&seed) == 0) + return seed; #endif #if defined HAVE_DEV_RANDOM && HAVE_DEV_RANDOM - if (has_dev_urandom()) - return get_dev_random_seed(); + if (get_dev_random_seed(&seed) == 0) + return seed; #endif #if defined HAVE_CRYPTGENRANDOM && HAVE_CRYPTGENRANDOM - return get_cryptgenrandom_seed(); + if (get_cryptgenrandom_seed(&seed) == 0) + return seed; #endif return get_time_seed(); } From 987d3b2c86748299f2ceb83345264c6aaa8e1db6 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Thu, 17 Dec 2020 19:59:37 -0800 Subject: [PATCH 85/94] fix compilation with clang Fixes the following warning: json_pointer.c:230:7: warning: implicit declaration of function 'vasprintf' is invalid in C99 [-Wimplicit-function-declaration] rc = vasprintf(&path_copy, path_fmt, args); --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2333d08..892aebb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -269,7 +269,7 @@ message(STATUS "Wrote ${PROJECT_BINARY_DIR}/config.h") configure_file(${PROJECT_SOURCE_DIR}/cmake/json_config.h.in ${PROJECT_BINARY_DIR}/json_config.h) message(STATUS "Wrote ${PROJECT_BINARY_DIR}/json_config.h") -if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") +if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections") if ("${DISABLE_WERROR}" STREQUAL "OFF") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") From 69d650528da0e23654065f4efc26c469bdae663c Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Wed, 13 Jan 2021 01:30:16 +0000 Subject: [PATCH 86/94] Keep the doc directory in the nodoc release tarball, just exclude its contents. --- RELEASE_CHECKLIST.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_CHECKLIST.txt b/RELEASE_CHECKLIST.txt index 8e70617..9f6b6db 100644 --- a/RELEASE_CHECKLIST.txt +++ b/RELEASE_CHECKLIST.txt @@ -93,7 +93,7 @@ Create the release tarballs: echo .git > excludes tar -czf json-c-${release}.tar.gz -X excludes json-c-${release} - echo doc >> excludes + echo 'doc/*' >> excludes tar -czf json-c-${release}-nodoc.tar.gz -X excludes json-c-${release} ------------ From 0f61f6921b2e4395d1e354ad356137e44d6a7e11 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Wed, 13 Jan 2021 01:57:25 +0000 Subject: [PATCH 87/94] Iesue #692: use arc4random() if it's available (in libc on BSD systems, and libbsd on Linux). --- CMakeLists.txt | 11 +++++++++++ cmake/config.h.in | 6 ++++++ random_seed.c | 13 +++++++++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 892aebb..30b4f2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,6 +170,17 @@ check_symbol_exists(vasprintf "stdio.h" HAVE_VASPRINTF) check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF) check_symbol_exists(vprintf "stdio.h" HAVE_VPRINTF) +check_symbol_exists(arc4random "stdlib.h" HAVE_ARC4RANDOM) +if (NOT HAVE_ARC4RANDOM) + check_include_file(bsd/stdlib.h HAVE_BSD_STDLIB_H) + if (HAVE_BSD_STDLIB_H) + list(APPEND CMAKE_REQUIRED_LIBRARIES "-lbsd") + link_libraries(bsd) + unset(HAVE_ARC4RANDOM CACHE) + check_symbol_exists(arc4random "bsd/stdlib.h" HAVE_ARC4RANDOM) + endif() +endif() + if (HAVE_FCNTL_H) check_symbol_exists(open "fcntl.h" HAVE_OPEN) endif() diff --git a/cmake/config.h.in b/cmake/config.h.in index 9e097cb..be0202a 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -74,6 +74,12 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_XLOCALE_H +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_BSD_STDLIB_H + +/* Define to 1 if you have `arc4random' */ +#cmakedefine HAVE_ARC4RANDOM + /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #cmakedefine HAVE_DOPRNT diff --git a/random_seed.c b/random_seed.c index ff5338f..f3ee740 100644 --- a/random_seed.c +++ b/random_seed.c @@ -13,6 +13,10 @@ #include "config.h" #include "strerror_override.h" #include +#include +#ifdef HAVE_BSD_STDLIB_H +#include +#endif #define DEBUG_SEED(s) @@ -168,7 +172,8 @@ static int get_getrandom_seed(int *seed) ssize_t ret; - do { + do + { ret = getrandom(seed, sizeof(*seed), GRND_NONBLOCK); } while ((ret == -1) && (errno == EINTR)); @@ -273,7 +278,7 @@ static int get_cryptgenrandom_seed(int *seed) } else { - BOOL ret = CryptGenRandom(hProvider, sizeof(*seed), (BYTE*)seed); + BOOL ret = CryptGenRandom(hProvider, sizeof(*seed), (BYTE *)seed); CryptReleaseContext(hProvider, 0); if (!ret) { @@ -310,6 +315,10 @@ int json_c_get_random_seed(void) if (has_rdrand()) return get_rdrand_seed(); #endif +#ifdef HAVE_ARC4RANDOM + /* arc4random never fails, so use it if it's available */ + return arc4random(); +#endif #ifdef HAVE_GETRANDOM if (get_getrandom_seed(&seed) == 0) return seed; From c456963110fa5af9a209218c718d81033ad53669 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Fri, 5 Feb 2021 18:58:20 +0300 Subject: [PATCH 88/94] Update json_object.c --- json_object.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/json_object.c b/json_object.c index b42026b..c15a477 100644 --- a/json_object.c +++ b/json_object.c @@ -235,7 +235,7 @@ static int json_escape_str(struct printbuf *pb, const char *str, size_t len, int break; } - if (pos - start_offset > 0) + if (pos > start_offset) printbuf_memappend(pb, str + start_offset, pos - start_offset); if (c == '\b') @@ -261,7 +261,7 @@ static int json_escape_str(struct printbuf *pb, const char *str, size_t len, int if (c < ' ') { char sbuf[7]; - if (pos - start_offset > 0) + if (pos > start_offset) printbuf_memappend(pb, str + start_offset, pos - start_offset); snprintf(sbuf, sizeof(sbuf), "\\u00%c%c", json_hex_chars[c >> 4], @@ -273,7 +273,7 @@ static int json_escape_str(struct printbuf *pb, const char *str, size_t len, int pos++; } } - if (pos - start_offset > 0) + if (pos > start_offset) printbuf_memappend(pb, str + start_offset, pos - start_offset); return 0; } From f787810890b91b2b141ce7630d5be85c5f8cfcc3 Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Sat, 13 Feb 2021 03:23:58 +0000 Subject: [PATCH 89/94] If arc4random is used, don't bother compiling in the other fallback methods since they'll never be used. Fixes PR#695 about unreachable code too. --- random_seed.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/random_seed.c b/random_seed.c index f3ee740..b2e8ce6 100644 --- a/random_seed.c +++ b/random_seed.c @@ -20,6 +20,16 @@ #define DEBUG_SEED(s) +#if defined(__APPLE__) || defined(__unix__) || defined(__linux__) +#define HAVE_DEV_RANDOM 1 +#endif + +#ifdef HAVE_ARC4RANDOM +#undef HAVE_GETRANDOM +#undef HAVE_DEV_RANDOM +#undef HAVE_CRYPTGENRANDOM +#endif + #if defined ENABLE_RDRAND /* cpuid */ @@ -197,7 +207,7 @@ static int get_getrandom_seed(int *seed) /* get_dev_random_seed */ -#if defined(__APPLE__) || defined(__unix__) || defined(__linux__) +#ifdef HAVE_DEV_RANDOM #include #include @@ -207,8 +217,6 @@ static int get_getrandom_seed(int *seed) #include #include -#define HAVE_DEV_RANDOM 1 - static const char *dev_random_file = "/dev/urandom"; static int get_dev_random_seed(int *seed) @@ -294,6 +302,7 @@ static int get_cryptgenrandom_seed(int *seed) /* get_time_seed */ +#ifndef HAVE_ARC4RANDOM #include static int get_time_seed(void) @@ -302,12 +311,12 @@ static int get_time_seed(void) return (unsigned)time(NULL) * 433494437; } +#endif /* json_c_get_random_seed */ int json_c_get_random_seed(void) { - int seed; #ifdef OVERRIDE_GET_RANDOM_SEED OVERRIDE_GET_RANDOM_SEED; #endif @@ -318,18 +327,28 @@ int json_c_get_random_seed(void) #ifdef HAVE_ARC4RANDOM /* arc4random never fails, so use it if it's available */ return arc4random(); -#endif +#else #ifdef HAVE_GETRANDOM - if (get_getrandom_seed(&seed) == 0) - return seed; + { + int seed; + if (get_getrandom_seed(&seed) == 0) + return seed; + } #endif #if defined HAVE_DEV_RANDOM && HAVE_DEV_RANDOM - if (get_dev_random_seed(&seed) == 0) - return seed; + { + int seed; + if (get_dev_random_seed(&seed) == 0) + return seed; + } #endif #if defined HAVE_CRYPTGENRANDOM && HAVE_CRYPTGENRANDOM - if (get_cryptgenrandom_seed(&seed) == 0) - return seed; + { + int seed; + if (get_cryptgenrandom_seed(&seed) == 0) + return seed; + } #endif return get_time_seed(); +#endif /* !HAVE_ARC4RANDOM */ } From 041cef434afe0d0c6da8b6ac1d1fa26087246dda Mon Sep 17 00:00:00 2001 From: Eric Haszlakiewicz Date: Mon, 15 Feb 2021 20:19:56 +0000 Subject: [PATCH 90/94] Add a DISABLE_EXTRA_LIBS option to skip using libbsd, per @neheb's request on issue #692/commit 0f61f692. --- CMakeLists.txt | 3 ++- cmake-configure | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 30b4f2d..79038aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,7 @@ option(DISABLE_WERROR "Avoid treating compiler warnings as fatal option(ENABLE_RDRAND "Enable RDRAND Hardware RNG Hash Seed." OFF) option(ENABLE_THREADING "Enable partial threading support." OFF) option(OVERRIDE_GET_RANDOM_SEED "Override json_c_get_random_seed() with custom code." OFF) +option(DISABLE_EXTRA_LIBS "Avoid linking against extra libraries, such as libbsd." OFF) if (UNIX OR MINGW OR CYGWIN) @@ -171,7 +172,7 @@ check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF) check_symbol_exists(vprintf "stdio.h" HAVE_VPRINTF) check_symbol_exists(arc4random "stdlib.h" HAVE_ARC4RANDOM) -if (NOT HAVE_ARC4RANDOM) +if (NOT HAVE_ARC4RANDOM AND DISABLE_EXTRA_LIBS STREQUAL "OFF") check_include_file(bsd/stdlib.h HAVE_BSD_STDLIB_H) if (HAVE_BSD_STDLIB_H) list(APPEND CMAKE_REQUIRED_LIBRARIES "-lbsd") diff --git a/cmake-configure b/cmake-configure index c8e44ae..dc695e5 100755 --- a/cmake-configure +++ b/cmake-configure @@ -30,6 +30,7 @@ $0 [] [-- []] --enable-static build static libraries [default=yes] --disable-Bsymbolic Avoid linking with -Bsymbolic-function --disable-werror Avoid treating compiler warnings as fatal errors + --disable-extra-libs Avoid linking against extra libraries, such as libbsd EOF exit @@ -73,6 +74,9 @@ while [ $# -gt 0 ] ; do --disable-werror) FLAGS+=(-DDISABLE_WERROR=ON) ;; + --disable-extra-libs) + FLAGS+=(-DDISABLE_EXTRA_LIBS=ON) + ;; --) shift break From ba181548bca566d320899f7b78e5b753c0dba611 Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Tue, 2 Mar 2021 14:27:40 +0800 Subject: [PATCH 91/94] To avoid target exe file export JSON functions. --- CMakeLists.txt | 4 ++++ debug.h | 2 +- json_c_version.h | 2 +- json_types.h | 2 +- printbuf.h | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 79038aa..60fa7e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,10 @@ include(CMakePackageConfigHelpers) option(BUILD_SHARED_LIBS "Default to building shared libraries" ON) option(BUILD_STATIC_LIBS "Default to building static libraries" ON) +if (BUILD_SHARED_LIBS) + add_definitions(-D JSON_C_DLL) +endif() + # Generate a release merge and test it to verify the correctness of republishing the package. ADD_CUSTOM_TARGET(distcheck COMMAND make package_source diff --git a/debug.h b/debug.h index a24136b..7463f86 100644 --- a/debug.h +++ b/debug.h @@ -24,7 +24,7 @@ extern "C" { #endif #ifndef JSON_EXPORT -#if defined(_MSC_VER) +#if defined(_MSC_VER) && defined(JSON_C_DLL) #define JSON_EXPORT __declspec(dllexport) #else #define JSON_EXPORT extern diff --git a/json_c_version.h b/json_c_version.h index 00de4b3..d15ad64 100644 --- a/json_c_version.h +++ b/json_c_version.h @@ -24,7 +24,7 @@ extern "C" { #define JSON_C_VERSION "0.15.99" #ifndef JSON_EXPORT -#if defined(_MSC_VER) +#if defined(_MSC_VER) && defined(JSON_C_DLL) #define JSON_EXPORT __declspec(dllexport) #else #define JSON_EXPORT extern diff --git a/json_types.h b/json_types.h index 67f4497..b7e55ad 100644 --- a/json_types.h +++ b/json_types.h @@ -18,7 +18,7 @@ extern "C" { #endif #ifndef JSON_EXPORT -#if defined(_MSC_VER) +#if defined(_MSC_VER) && defined(JSON_C_DLL) #define JSON_EXPORT __declspec(dllexport) #else #define JSON_EXPORT extern diff --git a/printbuf.h b/printbuf.h index bfcbd2b..a0da668 100644 --- a/printbuf.h +++ b/printbuf.h @@ -24,7 +24,7 @@ #define _printbuf_h_ #ifndef JSON_EXPORT -#if defined(_MSC_VER) +#if defined(_MSC_VER) && defined(JSON_C_DLL) #define JSON_EXPORT __declspec(dllexport) #else #define JSON_EXPORT extern From 9c0565100afde7d40ef0a6b34e9df2bfe84f2735 Mon Sep 17 00:00:00 2001 From: Philosoph228 Date: Tue, 13 Apr 2021 00:12:35 +0500 Subject: [PATCH 92/94] random_seed: fix unused variable for win32 build --- random_seed.c | 1 - 1 file changed, 1 deletion(-) diff --git a/random_seed.c b/random_seed.c index b2e8ce6..f474e39 100644 --- a/random_seed.c +++ b/random_seed.c @@ -271,7 +271,6 @@ static int get_cryptgenrandom_seed(int *seed) { HCRYPTPROV hProvider = 0; DWORD dwFlags = CRYPT_VERIFYCONTEXT; - int r; DEBUG_SEED("get_cryptgenrandom_seed"); From 1f8b64f62c76cb23a8eb041fdde341db604aae75 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 16 Apr 2021 09:32:07 +0300 Subject: [PATCH 93/94] tests: CMakeLists.txt: move test names to variable The intent is to be able to disable some features that get built into the library. When we do that, we also need to disable some tests. It's easier when adjusting a variable that contains the list of test names, versus modifying the list in the foreach() statement. Signed-off-by: Alexandru Ardelean --- tests/CMakeLists.txt | 50 +++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0c5c26e..cccb5df 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -12,30 +12,32 @@ target_link_libraries(test2Formatted PRIVATE ${PROJECT_NAME}) include_directories(PUBLIC ${CMAKE_SOURCE_DIR}) -foreach(TESTNAME - test1 - test2 - test4 - testReplaceExisting - test_cast - test_charcase - test_compare - test_deep_copy - test_double_serializer - test_float - test_int_add - test_json_pointer - test_locale - test_null - test_parse - test_parse_int64 - test_printbuf - test_set_serializer - test_set_value - test_strerror - test_util_file - test_visit - test_object_iterator) +set(ALL_TEST_NAMES + test1 + test2 + test4 + testReplaceExisting + test_cast + test_charcase + test_compare + test_deep_copy + test_double_serializer + test_float + test_int_add + test_json_pointer + test_locale + test_null + test_parse + test_parse_int64 + test_printbuf + test_set_serializer + test_set_value + test_strerror + test_util_file + test_visit + test_object_iterator) + +foreach(TESTNAME ${ALL_TEST_NAMES}) add_executable(${TESTNAME} ${TESTNAME}.c) if(${TESTNAME} STREQUAL test_strerror OR ${TESTNAME} STREQUAL test_util_file) From 8abeebc9b20ee830867df1c21cfa87bd6fdbaa38 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 16 Apr 2021 09:42:07 +0300 Subject: [PATCH 94/94] json_pointer: allow the feature to be disabled Some users may not want to included it in their build/system. So allow a cmake symbol to disable it. A user can do 'cmake -DDISABLE_JSON_POINTER=ON ' and disable the json_pointer functionality. That saves about 17 KB (on an x86_64) machine. This may be useful on smaller embedded systems; even though the saving would be fewer kilobytes. One thing that also needs to change a bit, is that the 'json.h' be autogenerated via cmake, in order to conditionally include that "json_pointer.h" file. Signed-off-by: Alexandru Ardelean --- .gitignore | 1 + CMakeLists.txt | 15 ++++++++++++--- json.h => json.h.cmakein | 2 +- tests/CMakeLists.txt | 5 ++++- 4 files changed, 18 insertions(+), 5 deletions(-) rename json.h => json.h.cmakein (96%) diff --git a/.gitignore b/.gitignore index 1cdaf9b..8d2cb62 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,7 @@ # It's not good practice to build directly in the source tree # but ignore cmake auto-generated files anyway: /json_config.h +/json.h /config.h /json-c.pc /Makefile diff --git a/CMakeLists.txt b/CMakeLists.txt index 79038aa..887b4d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,7 @@ option(ENABLE_RDRAND "Enable RDRAND Hardware RNG Hash Seed." option(ENABLE_THREADING "Enable partial threading support." OFF) option(OVERRIDE_GET_RANDOM_SEED "Override json_c_get_random_seed() with custom code." OFF) option(DISABLE_EXTRA_LIBS "Avoid linking against extra libraries, such as libbsd." OFF) +option(DISABLE_JSON_POINTER "Disable JSON pointer (RFC6901) support." OFF) if (UNIX OR MINGW OR CYGWIN) @@ -370,14 +371,13 @@ set(JSON_C_PUBLIC_HEADERS # Note: config.h is _not_ included here ${PROJECT_BINARY_DIR}/json_config.h - ${PROJECT_SOURCE_DIR}/json.h + ${PROJECT_BINARY_DIR}/json.h ${PROJECT_SOURCE_DIR}/arraylist.h ${PROJECT_SOURCE_DIR}/debug.h ${PROJECT_SOURCE_DIR}/json_c_version.h ${PROJECT_SOURCE_DIR}/json_inttypes.h ${PROJECT_SOURCE_DIR}/json_object.h ${PROJECT_SOURCE_DIR}/json_object_iterator.h - ${PROJECT_SOURCE_DIR}/json_pointer.h ${PROJECT_SOURCE_DIR}/json_tokener.h ${PROJECT_SOURCE_DIR}/json_types.h ${PROJECT_SOURCE_DIR}/json_util.h @@ -404,7 +404,6 @@ set(JSON_C_SOURCES ${PROJECT_SOURCE_DIR}/json_c_version.c ${PROJECT_SOURCE_DIR}/json_object.c ${PROJECT_SOURCE_DIR}/json_object_iterator.c - ${PROJECT_SOURCE_DIR}/json_pointer.c ${PROJECT_SOURCE_DIR}/json_tokener.c ${PROJECT_SOURCE_DIR}/json_util.c ${PROJECT_SOURCE_DIR}/json_visit.c @@ -414,6 +413,16 @@ set(JSON_C_SOURCES ${PROJECT_SOURCE_DIR}/strerror_override.c ) +if (NOT DISABLE_JSON_POINTER) + set(JSON_C_PUBLIC_HEADERS ${JSON_C_PUBLIC_HEADERS} ${PROJECT_SOURCE_DIR}/json_pointer.h) + set(JSON_C_SOURCES ${JSON_C_SOURCES} ${PROJECT_SOURCE_DIR}/json_pointer.c) + set(JSON_H_JSON_POINTER "#include \"json_pointer.h\"") +else() + set(JSON_H_JSON_POINTER "") +endif() + +configure_file(json.h.cmakein ${PROJECT_BINARY_DIR}/json.h @ONLY) + include_directories(${PROJECT_SOURCE_DIR}) include_directories(${PROJECT_BINARY_DIR}) diff --git a/json.h b/json.h.cmakein similarity index 96% rename from json.h rename to json.h.cmakein index 6c3b43b..4fed013 100644 --- a/json.h +++ b/json.h.cmakein @@ -26,7 +26,7 @@ extern "C" { #include "json_c_version.h" #include "json_object.h" #include "json_object_iterator.h" -#include "json_pointer.h" +@JSON_H_JSON_POINTER@ #include "json_tokener.h" #include "json_util.h" #include "linkhash.h" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cccb5df..d7abf51 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -24,7 +24,6 @@ set(ALL_TEST_NAMES test_double_serializer test_float test_int_add - test_json_pointer test_locale test_null test_parse @@ -37,6 +36,10 @@ set(ALL_TEST_NAMES test_visit test_object_iterator) +if (NOT DISABLE_JSON_POINTER) + set(ALL_TEST_NAMES ${ALL_TEST_NAMES} test_json_pointer) +endif() + foreach(TESTNAME ${ALL_TEST_NAMES}) add_executable(${TESTNAME} ${TESTNAME}.c)