@@ -601,8 +601,13 @@ static void sort_object(cJSON * const object, const cJSON_bool case_sensitive)
601601 object -> child = sort_list (object -> child , case_sensitive );
602602}
603603
604- static cJSON_bool compare_json (cJSON * a , cJSON * b , const cJSON_bool case_sensitive )
604+ static cJSON_bool compare_json (cJSON * a , cJSON * b , size_t depth , const cJSON_bool case_sensitive )
605605{
606+ /* Prevent stack overflow from deeply nested JSON comparison (#995) */
607+ if (depth >= CJSON_NESTING_LIMIT )
608+ {
609+ return false;
610+ }
606611 if ((a == NULL ) || (b == NULL ) || ((a -> type & 0xFF ) != (b -> type & 0xFF )))
607612 {
608613 /* mismatched type. */
@@ -635,7 +640,7 @@ static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensiti
635640 case cJSON_Array :
636641 for ((void )(a = a -> child ), b = b -> child ; (a != NULL ) && (b != NULL ); (void )(a = a -> next ), b = b -> next )
637642 {
638- cJSON_bool identical = compare_json (a , b , case_sensitive );
643+ cJSON_bool identical = compare_json (a , b , depth + 1 , case_sensitive );
639644 if (!identical )
640645 {
641646 return false;
@@ -664,7 +669,7 @@ static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensiti
664669 /* missing member */
665670 return false;
666671 }
667- identical = compare_json (a , b , case_sensitive );
672+ identical = compare_json (a , b , depth + 1 , case_sensitive );
668673 if (!identical )
669674 {
670675 return false;
@@ -831,7 +836,7 @@ static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_
831836 else if (opcode == TEST )
832837 {
833838 /* compare value: {...} with the given path */
834- status = !compare_json (get_item_from_pointer (object , path -> valuestring , case_sensitive ), get_object_item (patch , "value" , case_sensitive ), case_sensitive );
839+ status = !compare_json (get_item_from_pointer (object , path -> valuestring , case_sensitive ), get_object_item (patch , "value" , case_sensitive ), 0 , case_sensitive );
835840 goto cleanup ;
836841 }
837842
@@ -1318,10 +1323,17 @@ CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object)
13181323 sort_object (object , true);
13191324}
13201325
1321- static cJSON * merge_patch (cJSON * target , const cJSON * const patch , const cJSON_bool case_sensitive )
1326+ static cJSON * merge_patch (cJSON * target , const cJSON * const patch , size_t depth , const cJSON_bool case_sensitive )
13221327{
13231328 cJSON * patch_child = NULL ;
13241329
1330+ /* Prevent stack overflow from deeply nested JSON merge patch (#995) */
1331+ if (depth >= CJSON_NESTING_LIMIT )
1332+ {
1333+ cJSON_Delete (target );
1334+ return NULL ;
1335+ }
1336+
13251337 if (!cJSON_IsObject (patch ))
13261338 {
13271339 /* scalar value, array or NULL, just duplicate */
@@ -1364,7 +1376,7 @@ static cJSON *merge_patch(cJSON *target, const cJSON * const patch, const cJSON_
13641376 replace_me = cJSON_DetachItemFromObject (target , patch_child -> string );
13651377 }
13661378
1367- replacement = merge_patch (replace_me , patch_child , case_sensitive );
1379+ replacement = merge_patch (replace_me , patch_child , depth + 1 , case_sensitive );
13681380 if (replacement == NULL )
13691381 {
13701382 cJSON_Delete (target );
@@ -1380,19 +1392,25 @@ static cJSON *merge_patch(cJSON *target, const cJSON * const patch, const cJSON_
13801392
13811393CJSON_PUBLIC (cJSON * ) cJSONUtils_MergePatch (cJSON * target , const cJSON * const patch )
13821394{
1383- return merge_patch (target , patch , false);
1395+ return merge_patch (target , patch , 0 , false);
13841396}
13851397
13861398CJSON_PUBLIC (cJSON * ) cJSONUtils_MergePatchCaseSensitive (cJSON * target , const cJSON * const patch )
13871399{
1388- return merge_patch (target , patch , true);
1400+ return merge_patch (target , patch , 0 , true);
13891401}
13901402
1391- static cJSON * generate_merge_patch (cJSON * const from , cJSON * const to , const cJSON_bool case_sensitive )
1403+ static cJSON * generate_merge_patch (cJSON * const from , cJSON * const to , size_t depth , const cJSON_bool case_sensitive )
13921404{
13931405 cJSON * from_child = NULL ;
13941406 cJSON * to_child = NULL ;
13951407 cJSON * patch = NULL ;
1408+ cJSON * sub_patch = NULL ;
1409+ /* Prevent stack overflow from deeply nested JSON generate merge patch (#995) */
1410+ if (depth >= CJSON_NESTING_LIMIT )
1411+ {
1412+ return NULL ;
1413+ }
13961414 if (to == NULL )
13971415 {
13981416 /* patch to delete everything */
@@ -1449,10 +1467,16 @@ static cJSON *generate_merge_patch(cJSON * const from, cJSON * const to, const c
14491467 else
14501468 {
14511469 /* object key exists in both objects */
1452- if (!compare_json (from_child , to_child , case_sensitive ))
1470+ if (!compare_json (from_child , to_child , 0 , case_sensitive ))
14531471 {
1472+ sub_patch = generate_merge_patch (from_child , to_child , depth + 1 , case_sensitive );
1473+ if (sub_patch == NULL )
1474+ {
1475+ cJSON_Delete (patch );
1476+ return NULL ;
1477+ }
14541478 /* not identical --> generate a patch */
1455- cJSON_AddItemToObject (patch , to_child -> string , cJSONUtils_GenerateMergePatch ( from_child , to_child ) );
1479+ cJSON_AddItemToObject (patch , to_child -> string , sub_patch );
14561480 }
14571481
14581482 /* next key in the object */
@@ -1472,10 +1496,10 @@ static cJSON *generate_merge_patch(cJSON * const from, cJSON * const to, const c
14721496
14731497CJSON_PUBLIC (cJSON * ) cJSONUtils_GenerateMergePatch (cJSON * const from , cJSON * const to )
14741498{
1475- return generate_merge_patch (from , to , false);
1499+ return generate_merge_patch (from , to , 0 , false);
14761500}
14771501
14781502CJSON_PUBLIC (cJSON * ) cJSONUtils_GenerateMergePatchCaseSensitive (cJSON * const from , cJSON * const to )
14791503{
1480- return generate_merge_patch (from , to , true);
1504+ return generate_merge_patch (from , to , 0 , true);
14811505}
0 commit comments