Summary
Running the full test-files/test_gap_json_advanced.ts against a perry-compiled binary exits with SIGSEGV (139) after producing 23 lines of output where node produces a different ordering and ~26+ lines. Pre-existing on v0.5.498.
The failure is masked by the test currently being part of the parity sweep — the parity comparison reports it as "output differs" without surfacing the segfault nature.
Bisection
| Lines included |
Compile |
Run exit |
| 1–50 |
ok |
0, 16 lines output |
| 1–70 |
ok |
0, 21 lines output |
| 1–100 |
ok |
139 (SIGSEGV), 23 lines output |
So the trigger is somewhere in lines 70–100, which contains:
try { JSON.stringify(circular); } catch … (lines 70–76)
JSON.stringify(withToJSON) where the object has a toJSON() method (lines 78–86)
- Nested
toJSON() (lines 88–97)
Each of these works in isolation:
- Plain circular-ref
JSON.stringify + try/catch → exits 0, prints expected true / true.
- Plain
toJSON() (single + nested) → exits 0, prints expected {"wrapped":42} / {"inner":"custom-7"}.
So the SIGSEGV is in the interaction between the earlier statements (replacer / reviver / pretty-print / circular-detect that already executed in lines 1–70) and the subsequent JSON.stringify calls in lines 78+. Likely some state in the JSON machinery (replacer-state? circular-detect set?) isn't reset between calls, and the next stringify dereferences a stale pointer.
Output divergence
Even before the segfault, perry's output ordering differs from node's first 23 lines — perry emits two extra lines ({"name":"Bob","city":"NYC"} and 42) that node doesn't, suggesting the replacer / reviver path also has a correctness bug that's worth investigating in the same area.
Repro
./target/release/perry test-files/test_gap_json_advanced.ts -o /tmp/jsadv && /tmp/jsadv ; echo $? → 139.
Summary
Running the full
test-files/test_gap_json_advanced.tsagainst a perry-compiled binary exits with SIGSEGV (139) after producing 23 lines of output where node produces a different ordering and ~26+ lines. Pre-existing on v0.5.498.The failure is masked by the test currently being part of the parity sweep — the parity comparison reports it as "output differs" without surfacing the segfault nature.
Bisection
So the trigger is somewhere in lines 70–100, which contains:
try { JSON.stringify(circular); } catch …(lines 70–76)JSON.stringify(withToJSON)where the object has atoJSON()method (lines 78–86)toJSON()(lines 88–97)Each of these works in isolation:
JSON.stringify+ try/catch → exits 0, prints expectedtrue / true.toJSON()(single + nested) → exits 0, prints expected{"wrapped":42}/{"inner":"custom-7"}.So the SIGSEGV is in the interaction between the earlier statements (replacer / reviver / pretty-print / circular-detect that already executed in lines 1–70) and the subsequent
JSON.stringifycalls in lines 78+. Likely some state in the JSON machinery (replacer-state? circular-detect set?) isn't reset between calls, and the next stringify dereferences a stale pointer.Output divergence
Even before the segfault, perry's output ordering differs from node's first 23 lines — perry emits two extra lines (
{"name":"Bob","city":"NYC"}and42) that node doesn't, suggesting the replacer / reviver path also has a correctness bug that's worth investigating in the same area.Repro
./target/release/perry test-files/test_gap_json_advanced.ts -o /tmp/jsadv && /tmp/jsadv ; echo $?→139.