mirror of
https://github.com/nlohmann/json.git
synced 2026-11-12 07:00:46 +00:00
Add JSON_RECURSION_DEPTH_LIMIT to set how deep value walks recurse (#6081)
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
1 parent
0660d78b9c
commit
1dae5a66b1
30 files changed
+1340
-95
No files matched your search
@@ -198,6 +198,16 @@ this is planned to become the default in version 4.0.0.
|
||||
|
||||
See [full documentation of `JSON_PRECISE_STREAM_POSITION`](../api/macros/json_precise_stream_position.md).
|
||||
|
||||
## `JSON_RECURSION_DEPTH_LIMIT`
|
||||
|
||||
Sets the number of nesting levels that the operations walking a value (copying, comparing, serializing, hashing,
|
||||
merging, diffing, converting, destroying, and the binary writers) recurse into on the call stack before they continue
|
||||
with an explicit stack on the heap. The default is `128`; allowed are the integers from `0` to `254`. Lower it for
|
||||
threads with small stacks, raise it to trade stack for speed. Results are the same for every setting; the value must be
|
||||
the same in all translation units of a program.
|
||||
|
||||
See [full documentation of `JSON_RECURSION_DEPTH_LIMIT`](../api/macros/json_recursion_depth_limit.md).
|
||||
|
||||
## `JSON_SKIP_LIBRARY_VERSION_CHECK`
|
||||
|
||||
When defined, the library will not create a compiler warning when a different version of the library was already
|
||||
|
||||
@@ -54,10 +54,32 @@ Once a value has been parsed, operations that walk it recursively — serializin
|
||||
[`dump`](../../api/basic_json/dump.md), hashing it, copying it, comparing two values with `#!cpp ==`, `#!cpp <`, or (in
|
||||
C++20) `#!cpp <=>`, merging with [`update`](../../api/basic_json/update.md), applying a
|
||||
[`merge_patch`](../../api/basic_json/merge_patch.md), creating a patch with [`diff`](../../api/basic_json/diff.md) or
|
||||
[`merge_diff`](../../api/basic_json/merge_diff.md), [`flatten`](../../api/basic_json/flatten.md), and the binary
|
||||
writers (`to_cbor`, `to_msgpack`, ...) — descend at most 128 levels on the call stack and continue
|
||||
below that with an explicit stack instead, so none of them can exhaust the stack either, however deeply the value is
|
||||
nested. Destroying a value (its destructor) never recurses at all, regardless of nesting depth, for the same reason.
|
||||
[`merge_diff`](../../api/basic_json/merge_diff.md), converting it to another `basic_json` type, destroying it, and the
|
||||
binary writers (`to_cbor`, `to_msgpack`, ...) — descend at most
|
||||
[`JSON_RECURSION_DEPTH_LIMIT`](../../api/macros/json_recursion_depth_limit.md) levels on the call stack, 128 by default,
|
||||
and continue below that with an explicit stack on the heap. So the call stack does not grow with the nesting depth of the
|
||||
value, however deeply it is nested. ([`flatten`](../../api/basic_json/flatten.md),
|
||||
[`unflatten`](../../api/basic_json/unflatten.md), and [`to_bson`](../../api/basic_json/to_bson.md) never use the call
|
||||
stack for the nesting.)
|
||||
|
||||
The call stack still needs room for the levels that are recursed into, and the default limit assumes a stack of ordinary
|
||||
size. The stack that an operation needs is roughly proportional to the limit; with the default of 128 levels, the most
|
||||
demanding operation (`dump` in an unoptimized build) needed up to 288 KiB, and an optimized build needed 48 KiB or less,
|
||||
in measurements on macOS with arm64. The most demanding operation needed this much stack at the limits `0`, `32`,
|
||||
`128`, and `254`:
|
||||
|
||||
| Stack needed, in KiB | limit 0 | limit 32 | limit 128 (default) | limit 254 |
|
||||
|---|---:|---:|---:|---:|
|
||||
| unoptimized build (`-O0`) | 16 or less | 80 | 288 | 576 |
|
||||
| optimized build (`-O2`) | 16 or less | 16 or less | 48 | 112 |
|
||||
|
||||
A thread with a smaller stack (a task of a real-time operating system, a fiber, or a thread of the musl C library, whose
|
||||
default stack is 128 KiB) can still overflow its stack on deeply nested input, which is why the limit can be lowered:
|
||||
define `JSON_RECURSION_DEPTH_LIMIT` to a smaller value, down to `0`, before including the library. Such a limit changes
|
||||
only the stack that is needed and the speed (values nested more deeply than the limit are walked more slowly), never a
|
||||
result. See the [documentation of the macro](../../api/macros/json_recursion_depth_limit.md) for the complete tables,
|
||||
the speed, and the rules for choosing a value. Destroying a value (its destructor) recurses over the same number of
|
||||
levels and then continues without the call stack, and needs 32 KiB or less at every limit.
|
||||
|
||||
## Input size
|
||||
|
||||
|
||||
Reference in new issue
Block a user