fix: avoid quadratic re-scan of comments after a value (#1689) * fix: avoid quadratic re-scan of comments after a value OurReader::readComment() decides whether a comment should be attached to the previous value (commentAfterOnSameLine) by scanning the input from the end of that value up to the comment with containsNewLine(). lastValueEnd_ only advances when a new value is read, so a long run of comments after a value (e.g. during error recovery, or a value followed by many comments) made every comment re-scan the same growing prefix, giving O(n^2) parse time. A jsoncpp_fuzzer testcase took ~18s for a 400KB input. A comment can only ever be on the same line as the last value if no newline separates them, and the gap to inspect only grows as further comments are consumed, so once the gap has been examined for the first comment it never needs to be examined again. Mark lastValueHasAComment_ after the first comment following a value so subsequent comments skip the scan. Parsing the testcase drops from ~18s to ~56ms with identical output. Add a regression test that parses a value followed by a large number of trailing comments and requires it to complete well under a generous time bound. * test: assert linear comment scanning deterministically Replace the wall-clock bound in the comment regression test with a direct, deterministic assertion on work done. The parse output is identical with and without the fix, so the only observable difference is how much the parser scans; a time bound is also flaky under valgrind/sanitizers/loaded CI. Add an instrumentation counter for the bytes examined by OurReader::containsNewLine, exposed via a JSON_API seam, and assert it stays linear in the input (scanned < 4 * doc.size()) rather than O(comments * gap). The counter is thread_local (no race during concurrent parsing) and the increment is negligible, running only while parsing comments. It is compiled unconditionally because the ABI compatibility job builds the test suite against a separately-installed Release library, so the symbol must exist there. Rename the test to parseCommentsAfterValueScansLinearly to describe what it checks, and link crbug.com/521541633. Verified: the test fails when the fix is reverted and passes with it, in Debug and Release, and the seam links against a Release-installed shared library (the ABI compatibility scenario). --------- Co-authored-by: Jordan Bayles <jophba@chromium.org>
JSON is a lightweight data-interchange format. It can represent numbers, strings, ordered sequences of values, and collections of name/value pairs.
JsonCpp is a C++ library that allows manipulating JSON values, including serialization and deserialization to and from strings. It can also preserve existing comment in deserialization/serialization steps, making it a convenient format to store user input files.
JsonCpp is a mature project in maintenance mode. Our priority is providing a stable, reliable JSON library for the long tail of C++ development.
JsonCpp remains a primary choice for developers who require comment preservation and support for legacy toolchains where modern C++ standards are unavailable. The library is intended to be a reliable dependency that does not require frequent updates or major migration efforts.
1.y.z (master): Actively maintained. Requires C++11.
0.y.z: Legacy support for pre-C++11 compilers. Maintenance is limited to critical security fixes.
00.11.z: Discontinued.
Major versions maintain binary compatibility. Critical security fixes are accepted for both the master and 0.y.z branches.
[!NOTE] Package manager ports (vcpkg, Conan, etc.) are community-maintained. Please report outdated versions or missing generators to their respective repositories.
meson wrap install jsoncpp
For projects requiring a single-header approach, JsonCpp provides a script to generate an amalgamated source and header file.
You can generate the amalgamated files by running the following Python script from the top-level directory:
python3 amalgamate.py
This will generate a dist directory containing jsoncpp.cpp, json/json.h, and json/json-forwards.h. You can then drop these files directly into your project's source tree and compile jsoncpp.cpp alongside your other source files.
Documentation is generated via Doxygen. Additional information is available on the Project Wiki.
JsonCpp is licensed under the MIT license, or public domain where recognized. See LICENSE for details.