JSOM 2.0.0 — RFC 8259 conformance, bounded recursion, one parser
JSOM 2.0.0 — every input is safe, the spec is enforced, one parser.
Breaking changes
- Recursion is bounded. Documents nested deeper than 256 levels are rejected with
Maximum nesting depth exceeded (limit 256)instead of exhausting the C++ stack. The
limit isJsonParseOptions::max_depth(defaultlimits::MAX_NESTING_DEPTH= 256) and
every traversal honours it: parsing, serialization (compact and pretty), comparison,
path listing and formatting. - The RFC 8259 lexical rules are enforced on every parse, whatever the options:
a raw control character (U+0000–U+001F) inside a string,\uwithout exactly four hex
digits, any escape outside" \ / b f n r t u, and formfeed/vertical tab used as
whitespace are all syntax errors. Input that previously parsed leniently may now be
rejected — that is the point. - The event-based streaming API is gone:
StreamingParser,ParseEvents,PathNode,
DocumentBuilderandparse_document_streaming().parse_document()is the single
entry point (include/jsom/parse_document.hpp).
Security
- Unbounded recursion (CWE-674) fixed. ~60 KB of nested
[was enough to kill a
process with SIGSEGV — not an exception, so nothing could catch it. That is a remote
denial of service for anything parsing JSON from off-machine, and on a 1 MB
worker-thread stack about 3 KB sufficed. Now rejected, with the limit configurable so
callers on small stacks can lower it.
Conformance
- The nst/JSONTestSuite corpus is vendored and runnable in-tree
(cmake --build build --target run_conformance), parsing each file in a forked child
so that a crash is a result rather than a lost run. y_95/95 must-accept ·n_188/188 must-reject · 0 crashes with
--validation=numbers. By defaultn_is 162/188, because the number grammar stays
lenient unless asked.- Reference point: nlohmann/json 3.11.3 scores
y_95/95,n_187/188 on the same
corpus.
Added
JsonParseOptions::max_depthfor per-parse resource limits.- Opt-in number-grammar validation:
JsonParseOptions::validate_numbers,
ParsePresets::Validate, and--validation=lazy|numbersonjsom validateand
jsom format. tools/nesting_probe.cpp,tools/perf_probe.cpp— re-runnable measurement probes, so
the numbers inOPTIMIZATIONS.mdcan be reproduced.- Single-source versioning:
project(JSOM VERSION ...)generates<jsom/version.hpp>
(JSOM_VERSION,JSOM_VERSION_MAJOR/MINOR/PATCH); nothing else hard-codes a version.
Performance
- Faster than nlohmann/json 3.11.3 in all 17 paired benchmarks (1.02×–1.98×).
- Cost of the always-on lexical rules: +1.5% on string-heavy parsing, unmeasurable
elsewhere. Number validation: +6% (short numbers), +12% (17-digit), +0.5% (mixed) —
which is why it is opt-in.
Testing
- 185 tests (unit + regression), plus the same suite under ASan+UBSan, plus a fuzz target
that drives the parser in both configurations on every input and asserts
parse(to_json(doc)) == doc. jsom versionreports the version;CODING_STANDARDS.mddefines the gates
(zero warnings, tests, sanitizers, fuzzing, measured performance).