Skip to content

Commit 926e4f1

Browse files
fix(cjson_utils): add NULL check for cJSON_malloc in FindPointerFromObjectTo (#1049)
- Add missing NULL check for full_pointer allocation to prevent SIGSEGV on OOM. - Free target_pointer and return NULL safely if full_pointer fails to allocate. - Add oom_test unit test to verify graceful handling of memory allocation failure. Signed-off-by: JIgar-maheshwari-dev <maheshwarijigar656@gmail.com>
1 parent 1ac905d commit 926e4f1

3 files changed

Lines changed: 111 additions & 2 deletions

File tree

cJSON_Utils.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,12 @@ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const obje
203203
{
204204
/* reserve enough memory for a 64 bit integer + '/' and '\0' */
205205
unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + 20 + sizeof("/"));
206+
if(full_pointer == NULL)
207+
{
208+
/* Return early on allocation failure to prevent crash */
209+
cJSON_free(target_pointer);
210+
return NULL;
211+
}
206212
/* check if conversion to unsigned long is valid
207213
* This should be eliminated at compile time by dead code elimination
208214
* if size_t is an alias of unsigned long, or if it is bigger */
@@ -220,6 +226,12 @@ CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const obje
220226
if (cJSON_IsObject(object))
221227
{
222228
unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + pointer_encoded_length((unsigned char*)current_child->string) + 2);
229+
if(full_pointer == NULL)
230+
{
231+
/* Return early on allocation failure to prevent crash */
232+
cJSON_free(target_pointer);
233+
return NULL;
234+
}
223235
full_pointer[0] = '/';
224236
encode_string_as_pointer(full_pointer + 1, (unsigned char*)current_child->string);
225237
strcat((char*)full_pointer, (char*)target_pointer);
@@ -1091,6 +1103,11 @@ static void compose_patch(cJSON * const patches, const unsigned char * const ope
10911103
size_t suffix_length = pointer_encoded_length(suffix);
10921104
size_t path_length = strlen((const char*)path);
10931105
unsigned char *full_path = (unsigned char*)cJSON_malloc(path_length + suffix_length + sizeof("/"));
1106+
if(full_path == NULL)
1107+
{
1108+
/* Return early on allocation failure to prevent crash */
1109+
return;
1110+
}
10941111

10951112
sprintf((char*)full_path, "%s/", (const char*)path);
10961113
encode_string_as_pointer(full_path + path_length + 1, suffix);
@@ -1146,6 +1163,11 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa
11461163
cJSON *from_child = from->child;
11471164
cJSON *to_child = to->child;
11481165
unsigned char *new_path = (unsigned char*)cJSON_malloc(strlen((const char*)path) + 20 + sizeof("/")); /* Allow space for 64bit int. log10(2^64) = 20 */
1166+
if(new_path == NULL)
1167+
{
1168+
/* Return early on allocation failure to prevent crash */
1169+
return;
1170+
}
11491171

11501172
/* generate patches for all array elements that exist in both "from" and "to" */
11511173
for (index = 0; (from_child != NULL) && (to_child != NULL); (void)(from_child = from_child->next), (void)(to_child = to_child->next), index++)
@@ -1217,7 +1239,11 @@ static void create_patches(cJSON * const patches, const unsigned char * const pa
12171239
size_t path_length = strlen((const char*)path);
12181240
size_t from_child_name_length = pointer_encoded_length((unsigned char*)from_child->string);
12191241
unsigned char *new_path = (unsigned char*)cJSON_malloc(path_length + from_child_name_length + sizeof("/"));
1220-
1242+
if(new_path == NULL)
1243+
{
1244+
/* Return early on allocation failure to prevent crash */
1245+
return;
1246+
}
12211247
sprintf((char*)new_path, "%s/", path);
12221248
encode_string_as_pointer(new_path + path_length + 1, (unsigned char*)from_child->string);
12231249

tests/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ if(ENABLE_CJSON_TEST)
9393
set (cjson_utils_tests
9494
json_patch_tests
9595
old_utils_tests
96-
misc_utils_tests)
96+
misc_utils_tests
97+
oom_test)
9798

9899
foreach (cjson_utils_test ${cjson_utils_tests})
99100
add_executable("${cjson_utils_test}" "${cjson_utils_test}.c")

tests/oom_test.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
5+
#include "unity/examples/unity_config.h"
6+
#include "unity/src/unity.h"
7+
#include "../cJSON.h"
8+
#include "../cJSON_Utils.h"
9+
#include "common.h"
10+
11+
static int g_alloc_count = 0;
12+
static int g_fail_at = -1;
13+
14+
/* Custom malloc hook to simulate OOM on a specific allocation */
15+
static void* failing_malloc(size_t size)
16+
{
17+
int idx = g_alloc_count++;
18+
if (idx == g_fail_at)
19+
{
20+
return NULL; /* Simulate allocation failure */
21+
}
22+
return malloc(size);
23+
}
24+
25+
void setUp(void)
26+
{
27+
/* Declare variables at top of block */
28+
cJSON_Hooks hooks;
29+
30+
hooks.malloc_fn = failing_malloc;
31+
hooks.free_fn = free;
32+
33+
g_alloc_count = 0;
34+
g_fail_at = -1;
35+
36+
/* Register custom memory hook */
37+
cJSON_InitHooks(&hooks);
38+
}
39+
40+
void tearDown(void)
41+
{
42+
/* Reset hooks back to default */
43+
cJSON_InitHooks(NULL);
44+
}
45+
46+
static void find_pointer_should_handle_null_on_oom(void)
47+
{
48+
/* 1. ALL variable declarations MUST be at the very top */
49+
cJSON *root = NULL;
50+
cJSON *inner = NULL;
51+
cJSON *target = NULL;
52+
char *pointer = NULL;
53+
54+
/* 2. Executable code starts here */
55+
root = cJSON_CreateArray();
56+
inner = cJSON_CreateArray();
57+
cJSON_AddItemToArray(root, inner);
58+
59+
target = cJSON_CreateNumber(42);
60+
cJSON_AddItemToArray(inner, target);
61+
62+
/* Reset alloc counter right before calling FindPointer */
63+
g_alloc_count = 0;
64+
g_fail_at = 1;
65+
66+
pointer = cJSONUtils_FindPointerFromObjectTo(root, target);
67+
68+
/* Assertion */
69+
TEST_ASSERT_NULL(pointer);
70+
71+
/* Cleanup memory */
72+
cJSON_Delete(root);
73+
}
74+
75+
int CJSON_CDECL main(void)
76+
{
77+
UNITY_BEGIN();
78+
79+
RUN_TEST(find_pointer_should_handle_null_on_oom);
80+
81+
return UNITY_END();
82+
}

0 commit comments

Comments
 (0)