Compare commits

...

3 Commits

Author SHA1 Message Date
hexian000
4318635d48
Merge 6f9d1f7dd6 into c859b25da0 2025-09-09 17:44:01 +02:00
Alan Wang
c859b25da0
Release 1.7.19 (#958)
Some checks failed
CI / linux (CLANG, ENABLE_SANITIZERS) (push) Has been cancelled
CI / linux (CLANG, ENABLE_VALGRIND) (push) Has been cancelled
CI / linux (CLANG, NONE_MEM_CHECK) (push) Has been cancelled
CI / linux (GCC, ENABLE_SANITIZERS) (push) Has been cancelled
CI / linux (GCC, ENABLE_VALGRIND) (push) Has been cancelled
CI / linux (GCC, NONE_MEM_CHECK) (push) Has been cancelled
CI / macos (CLANG, ENABLE_SANITIZERS) (push) Has been cancelled
CI / macos (CLANG, ENABLE_VALGRIND) (push) Has been cancelled
CI / macos (CLANG, NONE_MEM_CHECK) (push) Has been cancelled
CI / macos (GCC, ENABLE_SANITIZERS) (push) Has been cancelled
CI / macos (GCC, ENABLE_VALGRIND) (push) Has been cancelled
CI / macos (GCC, NONE_MEM_CHECK) (push) Has been cancelled
2025-09-09 21:56:10 +08:00
He Xian
6f9d1f7dd6
"\u0000" is pretty valid in JSON string. Add valuestringlen to handle them in value.
Signed-off-by: He Xian <hexian000@outlook.com>
2024-11-16 16:09:47 +08:00
8 changed files with 113 additions and 32 deletions

View File

@ -1,3 +1,15 @@
1.7.19 (Sep 9, 2025)
======
Fixes:
------
* Fix indentation (should use spaces), see #814
* Fix spelling errors found by CodeSpell, see #841
* Check for NULL in cJSON_DetachItemViaPointer, fixes #882, see #886
* Fix #881, check overlap before calling strcpy in cJSON_SetValuestring, see #885
* Fix #880 Max recursion depth for cJSON_Duplicate to prevent stack exhaustion, see #888
* Allocate memory for the temporary buffer when paring numbers, see #939
* fix the incorrect check in decode_array_index_from_pointer, see #957
1.7.18 (May 13, 2024)
======
Fixes:

View File

@ -2,7 +2,7 @@ set(CMAKE_LEGACY_CYGWIN_WIN32 0)
cmake_minimum_required(VERSION 3.0)
project(cJSON
VERSION 1.7.18
VERSION 1.7.19
LANGUAGES C)
cmake_policy(SET CMP0054 NEW) # set CMP0054 policy

View File

@ -24,6 +24,7 @@ Contributors:
* [Debora Grosse](https://github.com/DeboraG)
* [dieyushi](https://github.com/dieyushi)
* [Dōngwén Huáng (黄东文)](https://github.com/DongwenHuang)
* [Dominik](https://github.com/DL6ER)
* [Donough Liu](https://github.com/ldm0)
* [Erez Oxman](https://github.com/erez-o)
* Eswar Yaganti
@ -80,6 +81,8 @@ Contributors:
* [Stephan Gatzka](https://github.com/gatzka)
* [Tony Langhammer](https://github.com/BigBrainAFK)
* [Vemake](https://github.com/vemakereporter)
* [vwvw](https://github.com/vwvw)
* [warmsocks](https://github.com/warmsocks)
* [Wei Tan](https://github.com/tan-wei)
* [Weston Schmidt](https://github.com/schmidtw)
* [xiaomianhehe](https://github.com/xiaomianhehe)

View File

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

106
cJSON.c
View File

@ -106,6 +106,20 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
return item->valuestring;
}
CJSON_PUBLIC(char *) cJSON_GetStringValueWithLength(const cJSON * const item, size_t *length)
{
if (!cJSON_IsString(item))
{
return NULL;
}
if(length != NULL)
{
*length = item->valuestringlen;
}
return item->valuestring;
}
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
{
if (!cJSON_IsNumber(item))
@ -117,7 +131,7 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
}
/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 18)
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 19)
#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
#endif
@ -206,6 +220,26 @@ static unsigned char* cJSON_strdup(const unsigned char* string, const internal_h
return copy;
}
static unsigned char* cJSON_strndup(const unsigned char* string, size_t length, const internal_hooks * const hooks)
{
unsigned char *copy = NULL;
if (string == NULL)
{
return NULL;
}
length += sizeof("");
copy = (unsigned char*)hooks->allocate(length);
if (copy == NULL)
{
return NULL;
}
memcpy(copy, string, length);
return copy;
}
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
{
if (hooks == NULL)
@ -428,6 +462,15 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
/* Note: when passing a NULL valuestring, cJSON_SetValuestring treats this as an error and return NULL */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
{
if (valuestring == NULL)
{
return NULL;
}
return cJSON_SetValuestringWithLength(object, valuestring, strlen(valuestring));
}
CJSON_PUBLIC(char*) cJSON_SetValuestringWithLength(cJSON *object, const char *valuestring, size_t valuestringlen)
{
char *copy = NULL;
size_t v1_len;
@ -443,20 +486,18 @@ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
return NULL;
}
v1_len = strlen(valuestring);
v2_len = strlen(object->valuestring);
v1_len = valuestringlen;
v2_len = object->valuestringlen;
if (v1_len <= v2_len)
{
/* strcpy does not handle overlapping string: [X1, X2] [Y1, Y2] => X2 < Y1 or Y2 < X1 */
if (!( valuestring + v1_len < object->valuestring || object->valuestring + v2_len < valuestring ))
{
return NULL;
}
strcpy(object->valuestring, valuestring);
/* memmove does handle overlapping string */
memmove(object->valuestring, valuestring, valuestringlen);
object->valuestring[valuestringlen] = '\0';
object->valuestringlen = valuestringlen;
return object->valuestring;
}
copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
copy = (char*) cJSON_strndup((const unsigned char*)valuestring, valuestringlen, &global_hooks);
if (copy == NULL)
{
return NULL;
@ -466,6 +507,7 @@ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
cJSON_free(object->valuestring);
}
object->valuestring = copy;
object->valuestringlen = valuestringlen;
return copy;
}
@ -924,6 +966,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu
item->type = cJSON_String;
item->valuestring = (char*)output;
item->valuestringlen = (size_t) (output_pointer - output);
input_buffer->offset = (size_t) (input_end - input_buffer->content);
input_buffer->offset++;
@ -945,10 +988,10 @@ fail:
return false;
}
/* Render the cstring provided to an escaped version that can be printed. */
static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
static cJSON_bool print_string_len(const unsigned char * const input, const size_t input_length, printbuffer * const output_buffer)
{
const unsigned char *input_pointer = NULL;
const unsigned char * const input_end = input + input_length;
unsigned char *output = NULL;
unsigned char *output_pointer = NULL;
size_t output_length = 0;
@ -974,7 +1017,7 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe
}
/* set "flag" to 1 if something needs to be escaped */
for (input_pointer = input; *input_pointer; input_pointer++)
for (input_pointer = input; input_pointer < input_end; input_pointer++)
{
switch (*input_pointer)
{
@ -1019,7 +1062,7 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe
output[0] = '\"';
output_pointer = output + 1;
/* copy the string */
for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
for (input_pointer = input; input_pointer < input_end; (void)input_pointer++, output_pointer++)
{
if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
{
@ -1067,10 +1110,16 @@ static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffe
return true;
}
/* Invoke print_string_ptr (which is useful) on an item. */
/* Render the cstring provided to an escaped version that can be printed. */
static cJSON_bool print_string_ptr(const char * const input, printbuffer * const output_buffer)
{
return print_string_len((const unsigned char*)input, input ? strlen(input) : 0, output_buffer);
}
/* Invoke print_string_len (which is useful) on an item. */
static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
{
return print_string_ptr((unsigned char*)item->valuestring, p);
return print_string_len((unsigned char*)item->valuestring, item->valuestringlen, p);
}
/* Predeclare these prototypes. */
@ -1464,7 +1513,7 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp
return false;
}
raw_length = strlen(item->valuestring) + sizeof("");
raw_length = item->valuestringlen + sizeof("");
output = ensure(output_buffer, raw_length);
if (output == NULL)
{
@ -1812,7 +1861,7 @@ static cJSON_bool print_object(const cJSON * const item, printbuffer * const out
}
/* print key */
if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
if (!print_string_ptr(current_item->string, output_buffer))
{
return false;
}
@ -2514,12 +2563,18 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
}
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
{
return cJSON_CreateStringWithLength(string, string ? strlen(string) : 0);
}
CJSON_PUBLIC(cJSON *) cJSON_CreateStringWithLength(const char *string, size_t length)
{
cJSON *item = cJSON_New_Item(&global_hooks);
if(item)
{
item->type = cJSON_String;
item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
item->valuestringlen = length;
item->valuestring = (char*)cJSON_strndup((const unsigned char*)string, length, &global_hooks);
if(!item->valuestring)
{
cJSON_Delete(item);
@ -2537,6 +2592,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
{
item->type = cJSON_String | cJSON_IsReference;
item->valuestring = (char*)cast_away_const(string);
item->valuestringlen = strlen(string);
}
return item;
@ -2569,7 +2625,8 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
if(item)
{
item->type = cJSON_Raw;
item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
item->valuestringlen = raw ? strlen(raw) : 0;
item->valuestring = (char*)cJSON_strndup((const unsigned char*)raw, item->valuestringlen, &global_hooks);
if(!item->valuestring)
{
cJSON_Delete(item);
@ -2795,7 +2852,8 @@ cJSON * cJSON_Duplicate_rec(const cJSON *item, size_t depth, cJSON_bool recurse)
newitem->valuedouble = item->valuedouble;
if (item->valuestring)
{
newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
newitem->valuestringlen = item->valuestringlen;
newitem->valuestring = (char*)cJSON_strndup((unsigned char*)item->valuestring, item->valuestringlen, &global_hooks);
if (!newitem->valuestring)
{
goto fail;
@ -3105,7 +3163,11 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons
{
return false;
}
if (strcmp(a->valuestring, b->valuestring) == 0)
if (a->valuestringlen != b->valuestringlen)
{
return false;
}
if (memcmp(a->valuestring, b->valuestring, a->valuestringlen) == 0)
{
return true;
}

View File

@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ
/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 18
#define CJSON_VERSION_PATCH 19
#include <stddef.h>
@ -113,6 +113,8 @@ typedef struct cJSON
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* Length of the item's string, useful for handling "\u0000" in string */
size_t valuestringlen;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
@ -183,6 +185,7 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* Check item type and return its value */
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
CJSON_PUBLIC(char *) cJSON_GetStringValueWithLength(const cJSON * const item, size_t *length);
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
/* These functions check the type of an item */
@ -204,6 +207,7 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringWithLength(const char *string, size_t length);
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
@ -284,6 +288,7 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
CJSON_PUBLIC(char*) cJSON_SetValuestringWithLength(cJSON *object, const char *valuestring, size_t valuestringlen);
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
#define cJSON_SetBoolValue(object, boolValue) ( \

View File

@ -238,7 +238,7 @@ static void cjson_should_not_follow_too_deep_circular_references(void)
static void cjson_set_number_value_should_set_numbers(void)
{
cJSON number[1] = {{NULL, NULL, NULL, cJSON_Number, NULL, 0, 0, NULL}};
cJSON number[1] = {{NULL, NULL, NULL, cJSON_Number, NULL, 0, 0, 0, NULL}};
cJSON_SetNumberValue(number, 1.5);
TEST_ASSERT_EQUAL(1, number->valueint);
@ -360,7 +360,7 @@ static void cjson_replace_item_via_pointer_should_replace_items(void)
static void cjson_replace_item_in_object_should_preserve_name(void)
{
cJSON root[1] = {{NULL, NULL, NULL, 0, NULL, 0, 0, NULL}};
cJSON root[1] = {{NULL, NULL, NULL, 0, NULL, 0, 0, 0, NULL}};
cJSON *child = NULL;
cJSON *replacement = NULL;
cJSON_bool flag = false;
@ -498,11 +498,10 @@ static void cjson_set_valuestring_should_return_null_if_strings_overlap(void)
str = cJSON_SetValuestring(obj, "abcde");
str += 1;
/* The string passed to strcpy overlap which is not allowed.*/
/* The string passed to strcpy overlap which is correctly copied.*/
str2 = cJSON_SetValuestring(obj, str);
/* If it overlaps, the string will be messed up.*/
TEST_ASSERT_TRUE(strcmp(str, "bcde") == 0);
TEST_ASSERT_NULL(str2);
/* If it overlaps, the string will not be messed up.*/
TEST_ASSERT_TRUE(strncmp(str2, "bcde", 4) == 0);
cJSON_Delete(obj);
}

View File

@ -34,7 +34,7 @@ static void assert_print_string(const char *expected, const char *input)
buffer.noalloc = true;
buffer.hooks = global_hooks;
TEST_ASSERT_TRUE_MESSAGE(print_string_ptr((const unsigned char*)input, &buffer), "Failed to print string.");
TEST_ASSERT_TRUE_MESSAGE(print_string_ptr(input, &buffer), "Failed to print string.");
TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, printed, "The printed string isn't as expected.");
}