[M0-CORE-07] Bounded JSON: JsonValue + parseJson/serializeJson + laige-fuzz json_parse target - #8
Merged
Merged
Conversation
…e-fuzz json_parse laige::JsonValue + parseJson/serializeJson (hand-rolled, bounded, no dependency — ADR 0003): recursive-descent parser with an RAII depth guard; JsonOptions defaults 1 MiB document / depth 32 (both inclusive). Every parse failure — grammar, escapes, duplicate keys, raw control characters, invalid UTF-8, lone surrogate halves, over size/depth — is ErrorCode::MalformedInput (no new codes; the registry entry for code 3 already names the ADR 0003 bounds). Numbers: strtod; a well-formed overflow token (e.g. 1e999) stores +/-inf (valid parse result, callers reject non-finite); integer literals beyond +/-2^53 lose precision (documented policy). Strings: strict UTF-8 (no overlong, no raw surrogates, <= U+10FFFF), two-character escapes, \uXXXX with required surrogate pairs. JsonValue: deep copy (O(size)), O(1) move with moved-from == Null, and the "owns exactly the payload its kind names" invariant kept by clearPayload() on every kind change and every assignment; deep equality (objects order-insensitive, arrays order-sensitive, NaN != NaN); findMember total on any value. Serializer: canonical compact ASCII (\uXXXX for control characters and every codepoint above 0x7F, surrogate pairs above U+FFFF), shortest correctly rounded decimal numbers via a %.*g search over p = 1..17 (deliberately not std::to_chars, which AppleClang 15 lacks for floats), -0.0 -> "0"; parse(serialize(v)) == v for all finite values; serializing a non-finite number is a documented precondition violation. laige-fuzz: minimal deterministic fuzz runner (this step's Verify gate requires it; M0-TEST-01 extends it): Prng-seeded (default seed 0x1F055EED, --runs/--seed), three input modes (mutate / truncate / random bytes) over a 19-document ASCII corpus; target json_parse registered; the fuzz_json_parse CTest entry runs in every build tree (instrumented in the ASan tree). Tests (ctest -R config_json, 25 cases): ConfigJsonValid (six kinds; DBL_MAX / denorm_min / +/-inf overflow / 2^53+1 rounding; escapes, surrogate pairs, strict UTF-8, DEL; containers, document order, depth-32 and 1 MiB boundary documents), ConfigJsonInvalid (trailing data, truncation, bad numbers, bad escapes, lone surrogates, raw controls, invalid UTF-8, duplicate keys, depth 33, 1 MiB+2 — every case asserts MalformedInput, not merely an error), ConfigJsonRoundTrip (parse -> serialize -> parse value stability plus serializer idempotence; canonical forms pinned), ConfigJsonValue (deep copy, moved-from Null, in-place replacement, kind transitions, deep equality, total findMember, churn), and ConfigJsonOptions (maxDepth 1/2; maxDocumentBytes inclusive bound and 0). Docs: docs/api/json.md (full API contract), building.md (current status: config_json + fuzz_json_parse entries; laige-fuzz minimal form from this step), tools/README.md, and the roadmap M0-CORE-07 entry checked off with the decision record. Verified locally 2026-09-11: 14/14 ctest on GCC 16.2.1 (static, shared, ASan+UBSan fatal, TSan halt_on_error=1) and Clang 22.1.8; laige-fuzz json_parse --runs=1000 clean under ASan (direct run with detect_leaks=1:halt_on_error=1); zero warnings under the NFR-8.10 policy. MSVC (windows lane) and AppleClang (macos lane) compilation to be proven by CI.
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
Implements roadmap step M0-CORE-07 (ADR 0003, D-JSON): the engine bounded JSON parser + value type + serializer in
laige-core, no new dependency, plus the minimal deterministic fuzz runner whosejson_parsetarget the step's Verify gate requires.laige::JsonValue+parseJson/serializeJson(src/laige-core/include/laige/json.h,json.cpp)JsonOptionsbounds (defaults: 1 MiB document, depth 32, both inclusive) — no recursion blowupErrorCode::MalformedInput— no new error codes (registry code 3 already names the ADR 0003 bounds)doubleviastrtod; overflow tokens store ±inf (valid parse result; callers reject non-finite); integers beyond ±2^53 lose precision (documented)JsonValue: deep copy, O(1) move (moved-from = Null), "owns exactly the payload its kind names" invariant; deep equality (objects order-insensitive, arrays order-sensitive, NaN != NaN)%.*gsearch over p=1..17 — deliberately notstd::to_chars, which AppleClang 15 lacks for floats)tools/fuzz/laige-fuzz.cpp: minimal deterministic runner (Prng-seeded, default seed0x1F055EED,--runs/--seed, mutate/truncate/random modes over a 19-document corpus); targetjson_parse; CTest entryfuzz_json_parseruns in every build tree (instrumented in the ASan tree). M0-TEST-01 extends it.docs/api/json.md(full contract),building.mdcurrent status,tools/README.md, roadmap entry checked off with decision recordVerify
ctest -R config_jsongreen — 25 GTest cases (ConfigJsonValid/ConfigJsonInvalid/ConfigJsonRoundTrip/ConfigJsonValue/ConfigJsonOptions); every invalid case assertsMalformedInputspecificallylaige-fuzz json_parse --runs=1000clean under ASan — instrumentedfuzz_json_parseCTest entry in the ASan tree, plus a direct run withASAN_OPTIONS=detect_leaks=1:halt_on_error=1Verified locally (2026-09-11)
build(static),build-shared(shared),build-asan(ASan+UBSan fatal),build-tsan(TSanhalt_on_error=1); 14/14 on Clang 22.1.8 (build-clang)-Wall -Werror -fno-exceptions -fno-rtti)Remaining for CI: MSVC (windows lane) and AppleClang (macos lane) compilation of the new sources.
Closes M0-CORE-07.