Compare commits

..

50 Commits

Author SHA1 Message Date
Max Bruckner
08738673be Reorder the context fields 2018-03-25 23:32:03 +02:00
Max Bruckner
1b001ab047 parse: Pull length calculation out. 2018-03-25 23:32:03 +02:00
Max Bruckner
409c2aaea7 cJSON_MakeDuplicateRecursive 2018-03-25 23:32:03 +02:00
Max Bruckner
e8f56bd194 Context: Add duplicate_recursive for cJSON_Duplicate 2018-03-25 23:32:03 +02:00
Max Bruckner
064eec8208 Change name from Configuration to Context 2018-03-25 23:32:03 +02:00
Max Bruckner
050f982608 cJSON_DuplicateConfiguration 2018-03-25 23:32:03 +02:00
Max Bruckner
d2d19127d3 cJSON_ConfigurationChangeParseEnd -> cJSON_ConfigurationGetParseEnd
This is probably a better approach than potentially having a pointer
that points to garbage on the stack and gets written to by cJSON.
2018-03-25 23:32:03 +02:00
Max Bruckner
691a83a479 cJSON_CreateConfig: Don't allow configuration, always use default 2018-03-25 23:32:03 +02:00
Max Bruckner
ae9dc3e7db cJSON_ConfigurationChangeAllowDataAfterJson 2018-03-25 23:32:03 +02:00
Max Bruckner
eeaaaac63e cJSON_ConfigurationChangeCaseSensitivity 2018-03-25 23:32:03 +02:00
Max Bruckner
78b5bed9a0 cJSON_ConfigurationChangeFormat 2018-03-25 23:32:03 +02:00
Max Bruckner
1a8f732749 cJSON_ConfigurationChangePrebufferSize 2018-03-25 23:32:03 +02:00
Max Bruckner
88c39fa2e4 cJSON_ConfigurationChangeParseEnd
Add a pointer to an end position of parsing to the cJSON_Configuration
object. (Essentially like return_parse_end, but as offset instead of
pointer).
2018-03-25 23:32:03 +02:00
Max Bruckner
9d801d64ea cJSON_CreateConfiguration, cJSON_ConfigurationChange{Allocators,Userdata} 2018-03-25 23:32:03 +02:00
Max Bruckner
877fac0f90 allocation helpers for allocating with a configuration 2018-03-25 23:32:03 +02:00
Max Bruckner
98e0b586ca Add cJSON_Allocators new style allocator struct 2018-03-25 23:32:03 +02:00
Max Bruckner
dd1ba72ce2 cJSON_Compare: Extract compare with internal_configuration 2018-03-25 23:32:03 +02:00
Max Bruckner
515d11f55a default_configuration: Macro for the internal_configuration defaults 2018-03-25 23:32:03 +02:00
Max Bruckner
ba8fe0f479 internal_configuration: Add case_sensitive 2018-03-25 23:32:03 +02:00
Max Bruckner
f02f79ecbb cJSON_ParseWithOpts: Extract pasrse with internal_configuration
Also introduces a allow_data_after_json property in the internal
configuration.
2018-03-25 23:32:03 +02:00
Max Bruckner
d4e81cfe57 cJSON_Delete: Extract delete_item with internal_configuration 2018-03-25 23:32:03 +02:00
Max Bruckner
7030dc7c5b Put buffer_size into internal_configuration 2018-03-25 23:32:03 +02:00
Max Bruckner
27977adc93 Put format into internal_configuration 2018-03-25 23:32:03 +02:00
Max Bruckner
677f0cb1bb Rename internal_hooks -> internal_configuration, cJSON_New_item -> create_item 2018-03-25 23:32:03 +02:00
Max Bruckner
3ebc06196a Gitignore: add CLion files 2018-03-25 23:31:36 +02:00
Max Bruckner
fd5281bdd8 cJSON: cjson_min: Wrap arguments in parentheses 2018-03-25 15:12:15 +02:00
Max Bruckner
1f4044a707 cJSON.c: Remove unused cast 2018-03-25 15:11:56 +02:00
Max Bruckner
08a2ad3c59 is_{nan,infinity}: Wrap macro arguments in parentheses 2018-03-25 14:25:46 +02:00
Max Bruckner
b06fb10f94 cJSON.c: Remove unnecessary includes 2018-03-25 14:20:48 +02:00
Max Bruckner
ce5f31ac47 Remove superfluous null checks in can_read/access_at_index macros 2018-03-25 13:01:49 +02:00
Max Bruckner
0715259635 cJSON_Compare: Performance improvement for objects
Check the size to prevent comparing objects equal if they are prefixes
of each other.
2018-03-25 13:01:10 +02:00
Max Bruckner
f4cc4d7c63 parse_value: Check only first character at first
This should improve performance
2018-03-25 13:01:10 +02:00
Max Bruckner
952b1017ab print_number: Introduce fast path for integers.
Thanks @Tangerino for suggesting this optimisation.
2018-03-25 13:01:10 +02:00
Max Bruckner
0914640d79 Extract helper: double_to_saturated_integer 2018-03-25 13:01:10 +02:00
Max Bruckner
5ed383a0d1 is_nan and is_infinity macros 2018-03-25 13:01:06 +02:00
Max Bruckner
3e2c29528a CMake: Remove -fsanitize=float-divide-by-zero
This is so that NaN and INFINITY values can be produced.
2018-03-25 13:00:12 +02:00
Max Bruckner
b2bbc11d44 Fix #234: Different argument names between declaration and definition 2018-03-25 13:00:12 +02:00
Max Bruckner
06f4152008 print: Comment about why the buffer is reallocated 2018-03-25 13:00:12 +02:00
Max Bruckner
0e0c463491 Release version 1.7.5 2018-03-22 20:29:17 +01:00
Max Bruckner
2336a0348d Contributors: Add Bob Kocisko 2018-03-22 20:28:54 +01:00
Max Bruckner
5d50f4efe1 Contributors: Thank all the non-code contributors 2018-03-22 20:28:30 +01:00
Max Bruckner
8abf110750 Merge pull request #251 from bobkocisko/master
json patch: adding to a subfield of a non-object now fails as expected
2018-03-22 20:00:24 +01:00
Bob Kocisko
d26a42af8d json patch: adding to a subfield of a non-object now fails as expected 2018-03-22 11:10:29 -04:00
Max Bruckner
6f264b5d0c Merge pull request #249 from DaveGamble/fix-add-item
Release 1.7.4
2018-03-02 20:04:29 +01:00
Max Bruckner
5da9edc8b1 Release version 1.7.4 2018-03-02 19:57:36 +01:00
Max Bruckner
22a7d04fa0 add_item_to_object: Fix use-after-free when string is aliased
If the `string` property of the item that is added is an alias to the
`string` parameter of `add_item_to_object`, and `constant` is false,
`cJSON_strdup` would access the string after it has been freed.

Thanks @hhallen for reporting this in #248.
2018-03-02 19:49:55 +01:00
Max Bruckner
a559eac472 Release version 1.7.3 2018-02-07 21:16:35 +01:00
Max Bruckner
d514bb866e Fix #241, potential double free 2018-02-07 19:36:59 +01:00
Max Bruckner
27caa364b0 Release version 1.7.2 2018-02-06 11:38:41 +01:00
Max Bruckner
f47271f455 Fix pkgconfig and installation. Thanks @zeerd for reporting
CMAKE_INSTALL_FULL_... needs to be used.
2018-02-06 11:24:03 +01:00
14 changed files with 193 additions and 91 deletions

2
.gitignore vendored
View File

@@ -14,3 +14,5 @@ libcjson.so.*
libcjson_utils.so.*
*.orig
.vscode
.idea
cmake-build-debug

View File

@@ -1,3 +1,27 @@
1.7.5
=====
Fixes:
------
* Fix a bug in the JSON Patch implementation of `cJSON Utils` (see #251), thanks @bobkocisko.
1.7.4
=====
Fixes:
------
* Fix potential use after free if the `string` parameter to `cJSON_AddItemToObject` is an alias of the `string` property of the object that is added (#248). Thanks @hhallen for reporting.
1.7.3
=====
Fixes:
------
* Fix potential double free, thanks @projectgus for reporting (see #241)
1.7.2
=====
Fixes:
------
* Fix the use of GNUInstallDirs variables and the pkgconfig file. Thanks @zeerd for reporting (see #240)
1.7.1
=====
Fixes:

View File

@@ -7,7 +7,7 @@ include(GNUInstallDirs)
set(PROJECT_VERSION_MAJOR 1)
set(PROJECT_VERSION_MINOR 7)
set(PROJECT_VERSION_PATCH 1)
set(PROJECT_VERSION_PATCH 5)
set(CJSON_VERSION_SO 1)
set(CJSON_UTILS_VERSION_SO 1)
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
@@ -106,12 +106,6 @@ endforeach()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${supported_compiler_flags}")
#variables for pkg-config
set(prefix "${CMAKE_INSTALL_PREFIX}")
set(libdir "${CMAKE_INSTALL_LIBDIR}")
set(version "${PROJECT_VERSION}")
set(includedir "${CMAKE_INSTALL_INCLUDEDIR}")
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
option(ENABLE_TARGET_EXPORT "Enable exporting of CMake targets. Disable when it causes problems!" ON)
@@ -148,15 +142,15 @@ endif()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" @ONLY)
install(FILES cJSON.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cjson")
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
install(TARGETS "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" EXPORT "${CJSON_LIB}")
install(FILES cJSON.h DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/cjson")
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson.pc" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig")
install(TARGETS "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" EXPORT "${CJSON_LIB}")
if (BUILD_SHARED_AND_STATIC_LIBS)
install(TARGETS "${CJSON_LIB}-static" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
install(TARGETS "${CJSON_LIB}-static" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}")
endif()
if(ENABLE_TARGET_EXPORT)
# export library information for CMake projects
install(EXPORT "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON")
install(EXPORT "${CJSON_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON")
endif()
set_target_properties("${CJSON_LIB}"
@@ -187,15 +181,15 @@ if(ENABLE_CJSON_UTILS)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/library_config/libcjson_utils.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" @ONLY)
install(TARGETS "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}" EXPORT "${CJSON_UTILS_LIB}")
install(TARGETS "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}" EXPORT "${CJSON_UTILS_LIB}")
if (BUILD_SHARED_AND_STATIC_LIBS)
install(TARGETS "${CJSON_UTILS_LIB}-static" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
install(TARGETS "${CJSON_UTILS_LIB}-static" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}")
endif()
install(FILES cJSON_Utils.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/cjson")
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
install(FILES cJSON_Utils.h DESTINATION "${CMAKE_INSTALL_FULL_INCLUDEDIR}/cjson")
install (FILES "${CMAKE_CURRENT_BINARY_DIR}/libcjson_utils.pc" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig")
if(ENABLE_TARGET_EXPORT)
# export library information for CMake projects
install(EXPORT "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON")
install(EXPORT "${CJSON_UTILS_LIB}" DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON")
endif()
set_target_properties("${CJSON_UTILS_LIB}"
@@ -215,7 +209,7 @@ configure_file(
# Install package config files
install(FILES ${PROJECT_BINARY_DIR}/cJSONConfig.cmake
${PROJECT_BINARY_DIR}/cJSONConfigVersion.cmake
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cJSON")
DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/cmake/cJSON")
option(ENABLE_CJSON_TEST "Enable building cJSON test" ON)
if(ENABLE_CJSON_TEST)

View File

@@ -7,6 +7,7 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB)
* [Ajay Bhargav](https://github.com/ajaybhargav)
* [Alper Akcan](https://github.com/alperakcan)
* [Anton Sergeev](https://github.com/anton-sergeev)
* [Bob Kocisko](https://github.com/bobkocisko)
* [Christian Schulze](https://github.com/ChristianSch)
* [Casperinous](https://github.com/Casperinous)
* [Debora Grosse](https://github.com/DeboraG)
@@ -42,3 +43,5 @@ Current Maintainer: [Max Bruckner](https://github.com/FSMaxB)
* [yangfl](https://github.com/yangfl)
And probably more people on [SourceForge](https://sourceforge.net/p/cjson/bugs/search/?q=status%3Aclosed-rejected+or+status%3Aclosed-out-of-date+or+status%3Awont-fix+or+status%3Aclosed-fixed+or+status%3Aclosed&page=0)
Also thanks to all the people who reported bugs and suggested new features.

View File

@@ -8,7 +8,7 @@ CJSON_TEST_SRC = cJSON.c test.c
LDLIBS = -lm
LIBVERSION = 1.7.1
LIBVERSION = 1.7.5
CJSON_SOVERSION = 1
UTILS_SOVERSION = 1

147
cJSON.c
View File

@@ -39,9 +39,7 @@
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
#include <limits.h>
#include <ctype.h>
@@ -82,7 +80,7 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) {
}
/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 1)
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 5)
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
#endif
@@ -121,12 +119,13 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned
typedef struct internal_context
{
size_t buffer_size;
size_t end_position;
void *userdata;
cJSON_Allocators allocators;
cJSON_bool format;
cJSON_bool allow_data_after_json;
cJSON_bool case_sensitive;
cJSON_Allocators allocators;
void *userdata;
size_t end_position;
cJSON_bool duplicate_recursive;
} internal_context;
#if defined(_MSC_VER)
@@ -195,16 +194,17 @@ static void deallocate(const internal_context * const context, void *pointer)
#define default_context {\
256, /* default buffer size */\
true, /* enable formatting by default */\
true, /* allow data after the JSON by default */\
true, /* case sensitive by default */\
0, /* default end position */\
NULL, /* no userdata */\
{\
malloc_wrapper,\
free_wrapper,\
realloc_wrapper\
},\
NULL, /* no userdata */\
0 /* default end position */\
true, /* enable formatting by default */\
true, /* allow data after the JSON by default */\
true, /* case sensitive by default */\
true /* Do cJSON_Duplicate recursively by default */\
}
/* this is necessary to assign the default context after initialization */
@@ -340,9 +340,9 @@ typedef struct
} parse_buffer;
/* check if the given size is left to read in a given parse buffer (starting with 1) */
#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
#define can_read(buffer, size) (((buffer)->offset + (size)) <= (buffer)->length)
/* check if the buffer can be accessed at the given index (starting with 0) */
#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
#define can_access_at_index(buffer, index) (((buffer)->offset + (index)) < (buffer)->length)
#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
/* get a pointer to the buffer at the position */
#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
@@ -529,8 +529,8 @@ static void update_offset(printbuffer * const buffer)
buffer->offset += strlen((const char*)buffer_pointer);
}
#define is_nan(number) (number != number)
#define is_infinity(number) (!is_nan(number) && (number * 0) != 0)
#define is_nan(number) ((number) != (number))
#define is_infinity(number) (!is_nan(number) && ((number) * 0) != 0)
/* Render the number nicely from the given item into a string. */
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
@@ -1038,6 +1038,7 @@ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
buffer->offset++;
}
/* step back if we went over the end */
if (buffer->offset == buffer->length)
{
buffer->offset--;
@@ -1063,7 +1064,7 @@ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
}
/* Parse an object - create a new root, and populate. */
static cJSON *parse(const char * const json, internal_context * const context)
static cJSON *parse(const char * const json, const size_t length, internal_context * const context)
{
parse_buffer buffer = { 0, 0, 0, 0, default_context };
cJSON *item = NULL;
@@ -1078,7 +1079,7 @@ static cJSON *parse(const char * const json, internal_context * const context)
}
buffer.content = (const unsigned char*)json;
buffer.length = strlen((const char*)json) + sizeof("");
buffer.length = length;
buffer.offset = 0;
buffer.context = *context;
@@ -1113,7 +1114,6 @@ fail:
delete_item(item, context);
}
if (json != NULL)
{
error local_error;
local_error.json = (const unsigned char*)json;
@@ -1141,8 +1141,13 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *json, const char **return_
internal_context context = global_context;
cJSON *item = NULL;
if (json == NULL)
{
return NULL;
}
context.allow_data_after_json = !require_null_terminated;
item = parse(json, &context);
item = parse(json, strlen((const char*)json) + sizeof(""), &context);
if (return_parse_end != NULL)
{
@@ -1155,10 +1160,15 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *json, const char **return_
/* Default options for cJSON_Parse */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *json)
{
return parse(json, &global_context);
if (json == NULL)
{
return NULL;
}
return parse(json, strlen((const char*)json) + sizeof(""), &global_context);
}
#define cjson_min(a, b) ((a < b) ? a : b)
#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
static unsigned char *print(const cJSON * const item, const internal_context * const context)
{
@@ -1397,10 +1407,6 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp
size_t raw_length = 0;
if (item->valuestring == NULL)
{
if (!output_buffer->noalloc)
{
deallocate(&output_buffer->context, output_buffer->buffer);
}
return false;
}
@@ -2000,32 +2006,37 @@ static void* cast_away_const(const void* string)
static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_context * const context, const cJSON_bool constant_key)
{
char *new_key = NULL;
int new_type = cJSON_Invalid;
if ((object == NULL) || (string == NULL) || (item == NULL))
{
return false;
}
if (constant_key)
{
new_key = (char*)cast_away_const(string);
new_type = item->type | cJSON_StringIsConst;
}
else
{
new_key = (char*)custom_strdup((const unsigned char*)string, context);
if (new_key == NULL)
{
return false;
}
new_type = item->type & ~cJSON_StringIsConst;
}
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
{
deallocate(context, item->string);
}
if (constant_key)
{
item->string = (char*)cast_away_const(string);
item->type |= cJSON_StringIsConst;
}
else
{
char *key = (char*)custom_strdup((const unsigned char*)string, context);
if (key == NULL)
{
return false;
}
item->string = key;
item->type &= ~cJSON_StringIsConst;
}
item->string = new_key;
item->type = new_type;
return add_item_to_array(object, item);
}
@@ -2638,56 +2649,60 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
return a;
}
/* Duplication */
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
static cJSON *duplicate_json(const cJSON *item, const internal_context * const context)
{
cJSON *newitem = NULL;
cJSON *child = NULL;
cJSON *next = NULL;
cJSON *newchild = NULL;
/* Bail on bad ptr */
if (!item)
if (item == NULL)
{
goto fail;
}
/* Create new item */
newitem = create_item(&global_context);
if (!newitem)
newitem = create_item(context);
if (newitem == NULL)
{
goto fail;
}
/* Copy over all vars */
newitem->type = item->type & (~cJSON_IsReference);
newitem->valueint = item->valueint;
newitem->valuedouble = item->valuedouble;
if (item->valuestring)
if (item->valuestring != NULL)
{
newitem->valuestring = (char*)custom_strdup((unsigned char*)item->valuestring, &global_context);
if (!newitem->valuestring)
newitem->valuestring = (char*)custom_strdup((unsigned char*)item->valuestring, context);
if (newitem->valuestring == NULL)
{
goto fail;
}
}
if (item->string)
if (item->string != NULL)
{
newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)custom_strdup((unsigned char*)item->string, &global_context);
newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)custom_strdup((unsigned char*)item->string, context);
if (!newitem->string)
{
goto fail;
}
}
/* If non-recursive, then we're done! */
if (!recurse)
if (!context->duplicate_recursive)
{
return newitem;
}
/* Walk the ->next chain for the child. */
child = item->child;
while (child != NULL)
{
newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
if (!newchild)
/* Each item in the ->next chain */
newchild = duplicate_json(child, context);
if (newchild == NULL)
{
goto fail;
}
@@ -2712,12 +2727,19 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
fail:
if (newitem != NULL)
{
delete_item(newitem, &global_context);
delete_item(newitem, context);
}
return NULL;
}
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
{
internal_context context = global_context;
context.duplicate_recursive = recurse;
return duplicate_json(item, &context);
}
CJSON_PUBLIC(void) cJSON_Minify(char *json)
{
unsigned char *into = (unsigned char*)json;
@@ -3011,6 +3033,17 @@ CJSON_PUBLIC(cJSON_Context) cJSON_AllowDataAfterJson(cJSON_Context context, cJSO
return context;
}
CJSON_PUBLIC(cJSON_Context) cJSON_MakeDuplicateRecursive(cJSON_Context context, cJSON_bool recursive)
{
if (context == NULL)
{
return NULL;
}
((internal_context*)context)->duplicate_recursive = recursive;
return context;
}
static cJSON_bool compare(const cJSON * const a, const cJSON * const b, const internal_context * const context)
{
if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))

View File

@@ -31,7 +31,7 @@ extern "C"
/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 1
#define CJSON_VERSION_PATCH 5
#include <stddef.h>
@@ -174,6 +174,8 @@ CJSON_PUBLIC(cJSON_Context) cJSON_SetFormat(cJSON_Context context, cJSON_Format
CJSON_PUBLIC(cJSON_Context) cJSON_MakeCaseSensitive(cJSON_Context context, cJSON_bool case_sensitive);
/* Change if data is allowed after the JSON */
CJSON_PUBLIC(cJSON_Context) cJSON_AllowDataAfterJson(cJSON_Context context, cJSON_bool allow_data_after_json);
/* Change if cJSON_Duplicate copies recursively */
CJSON_PUBLIC(cJSON_Context) cJSON_MakeDuplicateRecursive(cJSON_Context context, cJSON_bool recursive);
/* Supply malloc and free functions to cJSON globally */
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);

View File

@@ -988,6 +988,12 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_
cJSON_AddItemToObject(parent, (char*)child_pointer, value);
value = NULL;
}
else /* parent is not an object */
{
/* Couldn't find object to add to. */
status = 9;
goto cleanup;
}
cleanup:
if (value != NULL)

View File

@@ -2,8 +2,8 @@
set(CJSON_UTILS_FOUND @ENABLE_CJSON_UTILS@)
# The include directories used by cJSON
set(CJSON_INCLUDE_DIRS "@prefix@/@includedir@")
set(CJSON_INCLUDE_DIR "@prefix@/@includedir@")
set(CJSON_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
set(CJSON_INCLUDE_DIR "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)

View File

@@ -1,9 +1,8 @@
prefix=@prefix@
libdir=${prefix}/@libdir@
includedir=${prefix}/@includedir@
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: libcjson
Version: @version@
Version: @PROJECT_VERSION@
Description: Ultralightweight JSON parser in ANSI C
URL: https://github.com/DaveGamble/cJSON
Libs: -L${libdir} -lcjson

View File

@@ -1,9 +1,8 @@
prefix=@prefix@
libdir=${prefix}/@libdir@
includedir=${prefix}/@includedir@
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: libcjson_utils
Version: @version@
Version: @PROJECT_VERSION@
Description: An implementation of JSON Pointer, Patch and Merge Patch based on cJSON.
URL: https://github.com/DaveGamble/cJSON
Libs: -L${libdir} -lcjson_utils

View File

@@ -39,6 +39,7 @@ static void create_context_should_create_a_context(void)
TEST_ASSERT_TRUE_MESSAGE(context->case_sensitive, "case_sensitive has an incorrect value.");
TEST_ASSERT_TRUE_MESSAGE(context->allow_data_after_json, "allow_data_after_json has an incorrect value.");
TEST_ASSERT_NULL_MESSAGE(context->userdata, "Userdata should be NULL");
TEST_ASSERT_TRUE_MESSAGE(context->duplicate_recursive, "Duplicating is not recursive.");
TEST_ASSERT_TRUE_MESSAGE(malloc_wrapper == context->allocators.allocate, "Wrong malloc.");
TEST_ASSERT_TRUE_MESSAGE(realloc_wrapper == context->allocators.reallocate, "Wrong realloc.");
TEST_ASSERT_TRUE_MESSAGE(free_wrapper == context->allocators.deallocate, "Wrong free.");
@@ -240,6 +241,18 @@ static void allow_data_after_json_should_change_allow_data_after_json(void)
free(context);
}
static void make_duplicate_recursive_should_make_duplicate_recursive(void)
{
internal_context *context = (internal_context*)cJSON_CreateContext(NULL, NULL);
TEST_ASSERT_NOT_NULL(context);
context = (internal_context*)cJSON_MakeDuplicateRecursive(context, false);
TEST_ASSERT_NOT_NULL(context);
TEST_ASSERT_FALSE_MESSAGE(context->duplicate_recursive, "Duplicating is not set correctly.");
free(context);
}
int main(void)
{
UNITY_BEGIN();
@@ -259,6 +272,7 @@ int main(void)
RUN_TEST(set_format_should_set_format);
RUN_TEST(make_case_sensitive_should_change_case_sensitivity);
RUN_TEST(allow_data_after_json_should_change_allow_data_after_json);
RUN_TEST(make_duplicate_recursive_should_make_duplicate_recursive);
return UNITY_END();
}

View File

@@ -80,5 +80,12 @@
"doc": { "foo": ["bar"] },
"patch": [ { "op": "add", "path": "/foo/-", "value": ["abc", "def"] }],
"expected": {"foo": ["bar", ["abc", "def"]] }
}
},
{
"comment": "15",
"doc": {"foo": {"bar": 1}},
"patch": [{"op": "add", "path": "/foo/bar/baz", "value": "5"}],
"error": "attempting to add to subfield of non-object"
}
]

View File

@@ -10,8 +10,7 @@
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
@@ -420,7 +419,7 @@ static void *failing_realloc(void *pointer, size_t size, void *userdata)
static void ensure_should_fail_on_failed_realloc(void)
{
printbuffer buffer = {NULL, 10, 0, 0, false, {256, false, true, true, {malloc_wrapper, free_wrapper, failing_realloc}, NULL, 0 } };
printbuffer buffer = {NULL, 10, 0, 0, false, {256, 0, NULL, {malloc_wrapper, free_wrapper, failing_realloc}, false, true, true, true} };
buffer.context.userdata = &buffer;
buffer.buffer = (unsigned char*)malloc(100);
TEST_ASSERT_NOT_NULL(buffer.buffer);
@@ -510,6 +509,25 @@ static void cjson_create_array_reference_should_create_an_array_reference(void)
cJSON_Delete(number_reference);
}
static void cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased(void)
{
cJSON *object = cJSON_CreateObject();
cJSON *number = cJSON_CreateNumber(42);
char *name = (char*)custom_strdup((const unsigned char*)"number", &global_context);
TEST_ASSERT_NOT_NULL(object);
TEST_ASSERT_NOT_NULL(number);
TEST_ASSERT_NOT_NULL(name);
number->string = name;
/* The following should not have a use after free
* that would show up in valgrind or with AddressSanitizer */
cJSON_AddItemToObject(object, number->string, number);
cJSON_Delete(object);
}
static void is_nan_should_detect_nan(void)
{
double nan = 0.0/0.0;
@@ -550,6 +568,7 @@ int main(void)
RUN_TEST(cjson_create_string_reference_should_create_a_string_reference);
RUN_TEST(cjson_create_object_reference_should_create_an_object_reference);
RUN_TEST(cjson_create_array_reference_should_create_an_array_reference);
RUN_TEST(cjson_add_item_to_object_should_not_use_after_free_when_string_is_aliased);
RUN_TEST(is_nan_should_detect_nan);
RUN_TEST(is_infinity_should_detect_infinity);