背景
父任务:#132
Go encoding/json/jsontext.FuzzCoder 会随机读取 token/value,再写回,并验证重放后的 JSON 与原输入语义一致。qjson 没有流式 token API,但 Phase 2 有 root getter、cursor、object entry、array index、path getter 和 skip-cache,这些读取路径同样需要语义级 fuzz 覆盖。
当前仓库已有 fuzz_parse_lazy:它以 serde_json::Value 为语义 oracle,通过 qjson public cursor FFI 重建完整 JSON model,并覆盖部分 varied-order sibling lookup。本 issue 收敛为增强现有 fuzz_parse_lazy,不新增独立 fuzz target。
目标
将 fuzz_parse_lazy 明确定义为 qjson Phase 2 semantic replay fuzz target,覆盖遍历、访问顺序、root/cursor getter 一致性和 skip-cache cold/warm 路径,验证不同 Phase 2 读取方式得到一致语义。
重点覆盖:
- root cursor 全量遍历并重建 JSON semantic model。
qjson_cursor_object_entry_at 顺序遍历对象,覆盖所有 entry,包括 duplicate key。
qjson_cursor_field 按 varied order 访问对象字段,覆盖同一 container 的 cold path / warm skip-cache path。
qjson_cursor_index 按 varied order 访问数组元素,覆盖同一 container 的 cold path / warm skip-cache path。
- root getter 与 cursor getter 对同一路径结果一致。
- duplicate key、escaped key、path-like key、wide object、wide array、nested object/array、root scalar。
语义边界
- 语义 oracle 仍使用
serde_json::Value。
- 数字比较按 qjson getter 语义归一化为
f64,不把 serde 的 arbitrary precision number model 当作 qjson 承诺。
- object 的整体 semantic model 按 serde/qjson getter 可观察语义使用 last-wins。
qjson_cursor_object_entry_at replay 必须保留并检查所有 object entries,包括 duplicate key。
qjson_cursor_field / path getter 不对 duplicate key 断言等于 last-wins;duplicate key 通过顺序 entry replay 覆盖。
- root getter vs cursor getter 一致性只覆盖 qjson path 能无歧义表达的路径:路径上对象 key 在对应 parent 内唯一,且 key 不包含
., [, ]。
- Lua mutation/materialize/encode 的 duplicate-key 行为不属于本 issue:未修改对象保留原有 key/value;一旦修改则 last-wins,这由 Lua lazy table / materialize 相关测试覆盖。
建议实现
- 继续增强
fuzz/fuzz_targets/fuzz_parse_lazy.rs,不新增独立 target。
- 保留当前 serde oracle + qjson cursor replay 主流程。
- replay object 时通过
qjson_cursor_object_entry_at 顺序读取全部 entries,并用 last-wins model 与 serde 比较。
- replay array 时通过
qjson_cursor_index 顺序重建,并额外用 varied order 重读元素。
- 对 unique key object,用 varied order 重复调用
qjson_cursor_field,并与 entry replay 得到的 value 比较,以明确覆盖 skip-cache cold/warm path。
- 在 replay 过程中收集 path-safe leaves/container paths;对这些路径分别调用 root getter 和从 root cursor 出发的 cursor getter,断言 type/value/错误行为一致。
- string 使用
*_get_str,number 使用 *_get_f64,bool 使用 *_get_bool,container/null 使用 *_typeof / *_len 等不解码 value 的 API。
- 对触发过 bug 的随机访问顺序,最小化后提交为
fuzz/corpus/fuzz_parse_lazy/ regression corpus。
CI 与文档
- PR CI 继续通过
cargo +nightly fuzz run fuzz_parse_lazy -- -runs=0 replay corpus。
- scheduled timed fuzz 继续运行
fuzz_parse_lazy。
- corpus seed 至少覆盖 escaped key、duplicate key、path-like key、wide object、wide array、nested object/array 和 root scalar。
CONTRIBUTING.md 的 fuzzing 段落说明:fuzz_parse_lazy 是 Phase 2 semantic replay target,验证读取语义一致性;fuzz_parse_eager 验证 eager parse accept/reject;fuzz_ffi_ops 验证任意 FFI 操作序列的 panic-barrier 和 pointer-safety。
验收标准
fuzz_parse_lazy 覆盖 cursor replay、object_entry_at 顺序遍历、varied-order field/index lookup、root/cursor getter 一致性。
- path getter 一致性仅覆盖 path-safe unique-key 路径;duplicate key 和 path-like key 通过 entry replay 覆盖。
- skip-cache warm path 有明确覆盖机制,并在文档中说明。
- PR CI 能 replay
fuzz_parse_lazy corpus。
- scheduled timed fuzz 能运行
fuzz_parse_lazy。
- 文档说明
fuzz_parse_lazy 与 fuzz_parse_eager / fuzz_ffi_ops 的边界。
- 不把 Lua mutation/materialize/encode 的 duplicate-key 语义纳入本 issue。
背景
父任务:#132
Go
encoding/json/jsontext.FuzzCoder会随机读取 token/value,再写回,并验证重放后的 JSON 与原输入语义一致。qjson 没有流式 token API,但 Phase 2 有 root getter、cursor、object entry、array index、path getter 和 skip-cache,这些读取路径同样需要语义级 fuzz 覆盖。当前仓库已有
fuzz_parse_lazy:它以serde_json::Value为语义 oracle,通过 qjson public cursor FFI 重建完整 JSON model,并覆盖部分 varied-order sibling lookup。本 issue 收敛为增强现有fuzz_parse_lazy,不新增独立 fuzz target。目标
将
fuzz_parse_lazy明确定义为 qjson Phase 2 semantic replay fuzz target,覆盖遍历、访问顺序、root/cursor getter 一致性和 skip-cache cold/warm 路径,验证不同 Phase 2 读取方式得到一致语义。重点覆盖:
qjson_cursor_object_entry_at顺序遍历对象,覆盖所有 entry,包括 duplicate key。qjson_cursor_field按 varied order 访问对象字段,覆盖同一 container 的 cold path / warm skip-cache path。qjson_cursor_index按 varied order 访问数组元素,覆盖同一 container 的 cold path / warm skip-cache path。语义边界
serde_json::Value。f64,不把 serde 的 arbitrary precision number model 当作 qjson 承诺。qjson_cursor_object_entry_atreplay 必须保留并检查所有 object entries,包括 duplicate key。qjson_cursor_field/ path getter 不对 duplicate key 断言等于 last-wins;duplicate key 通过顺序 entry replay 覆盖。.,[,]。建议实现
fuzz/fuzz_targets/fuzz_parse_lazy.rs,不新增独立 target。qjson_cursor_object_entry_at顺序读取全部 entries,并用 last-wins model 与 serde 比较。qjson_cursor_index顺序重建,并额外用 varied order 重读元素。qjson_cursor_field,并与 entry replay 得到的 value 比较,以明确覆盖 skip-cache cold/warm path。*_get_str,number 使用*_get_f64,bool 使用*_get_bool,container/null 使用*_typeof/*_len等不解码 value 的 API。fuzz/corpus/fuzz_parse_lazy/regression corpus。CI 与文档
cargo +nightly fuzz run fuzz_parse_lazy -- -runs=0replay corpus。fuzz_parse_lazy。CONTRIBUTING.md的 fuzzing 段落说明:fuzz_parse_lazy是 Phase 2 semantic replay target,验证读取语义一致性;fuzz_parse_eager验证 eager parse accept/reject;fuzz_ffi_ops验证任意 FFI 操作序列的 panic-barrier 和 pointer-safety。验收标准
fuzz_parse_lazy覆盖 cursor replay、object_entry_at顺序遍历、varied-order field/index lookup、root/cursor getter 一致性。fuzz_parse_lazycorpus。fuzz_parse_lazy。fuzz_parse_lazy与fuzz_parse_eager/fuzz_ffi_ops的边界。