Repository navigation
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
cJSON_Comparewalks nested arrays and objects recursively without any depthcounter. Every other recursive tree walker in the library is bounded, so a
caller has no way to know that comparing two very deep trees can exhaust the
stack. On a 200k-deep tree it crashes.
This is a robustness / consistency fix, not a security report. A caller cannot
reach that depth from JSON text:
cJSON_Parseis already capped byCJSON_NESTING_LIMITand rejects deeper input (verified below). The tree has tobe built programmatically by the caller, or assembled by repeated JSON Patch
operations on an existing tree.
Related but distinct from #1093 (parser under ASan/-O0) and #995 (merge patch
recursion): this is about
cJSON_Compareonly.Repro
Harness: build two identical N-level nested arrays programmatically, then call
cJSON_Compare(a, b, 1). Built withcc -O2(no sanitizers), 8 MiB stack.Nested objects (
{"a":{"a":...}}) behave the same: depth 200,000 returns 0 andexits cleanly after the patch.
Why the existing limit does not apply
Recursion is bounded everywhere else in the library:
parse_array/parse_object— cJSON.c:1502 / 1667,input_buffer->depth >= CJSON_NESTING_LIMITprint_array/print_object— cJSON.c:1606 / 1791, same check (Fix: add depth check to prevent stack overflow in cJSON_Print #984)cJSON_Duplicate_rec— cJSON.c:2836,depth >= CJSON_CIRCULAR_LIMITcJSON_Compare(cJSON.c:3072) only checks NULL, type equality and thea == bshortcut, then self-recurses unconditionally at cJSON.c:3137 (array elements)
and cJSON.c:3167 / 3183 (object members, both directions).
compare_jsonin cJSON_Utils.c:604 has the same shape. I left it alone onpurpose — that file already has an open recursion report (#995) and I would
rather not mix the two discussions.
Patch
cJSON_Comparekeeps its exact signature and becomes a thin wrapper over anew static
compare_rec(a, b, case_sensitive, depth).CJSON_NESTING_LIMITand returnfalse(trees that deep are reportedunequal rather than crashing).
The guard is
depth > CJSON_NESTING_LIMITwith the root at depth 0, so nothingthat
cJSON_Parsecan produce is affected. Measured on the same commit: