Skip to content

fix(json): serialize TypedArray in JSON.stringify instead of SIGSEGV (#5111)#5114

Merged
proggeramlug merged 2 commits into
mainfrom
claude/issue-5111-ar4t5g
Jun 14, 2026
Merged

fix(json): serialize TypedArray in JSON.stringify instead of SIGSEGV (#5111)#5114
proggeramlug merged 2 commits into
mainfrom
claude/issue-5111-ar4t5g

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #5111.

Problem

JSON.stringify of a TypedArray segfaulted — the map/subarray results from the issue, but also slice/filter results and even a plain JSON.stringify(new Int32Array([1,2,3])).

Root cause

The stringify value dispatchers had no TypedArray arm. A TypedArrayHeader-backed view fell through to the gc_obj_type tag read — but small typed arrays are plain-alloc'd with no GcHeader, so reading 8 bytes before the header pulled in unrelated allocator metadata and dispatched to a random arm (the SIGSEGV). The Array.from/spread "garbage" symptom was the same mis-dispatch reading wrong element kinds/offsets.

This is exactly the hazard already handled for Buffer/Uint8Array (which also have no GcHeader): they're detected via a registry pre-check before gc_obj_type.

Fix

Detect a registered typed array via lookup_typed_array_kind before gc_obj_type, and serialize it in Node's index shape {"0":v,…}. Two new helpers in json/stringify.rs:

  • stringify_typed_array — compact form
  • stringify_typed_array_pretty — the space-indented form

wired into every buffer-dispatch site: stringify_value, stringify_value_depth, the nested array-element path, and the replacer/pretty walks in json/replacer.rs. Each element funnels through write_number, so NaN/±Infinity render as null and a BigInt64/BigUint64 element throws Node's TypeError: Do not know how to serialize a BigInt.

Verification

Output is byte-for-byte identical to node --experimental-strip-types for the typed array as a root value, an object field, and an array element, in both compact and 3-arg pretty forms — including map/subarray/slice/filter results, NaNnull, empty array → {}, and the BigInt throw. Array.from/spread of a map result now read correctly too.

  • New unit test: stringify_typed_array_emits_node_index_shape
  • Existing perry-runtime JSON test suite: 42 passed, 0 failed

https://claude.ai/code/session_014AH46fwU7BaRRxkMc5Zcq2


Generated by Claude Code

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Fixed JSON serialization crashes when processing typed array values
    • Improved detection and handling of typed arrays during serialization to prevent memory errors
    • Enhanced output format compatibility with standard JSON serialization
    • Added regression test to prevent future occurrences

…5111)

JSON.stringify of a TypedArray (a map/subarray/slice/filter result, or even a
plain `new Int32Array([...])`) segfaulted: the stringify value dispatchers had
no TypedArray arm, so a TypedArrayHeader-backed view reached the gc_obj_type
tag read — but small typed arrays are plain-alloc'd with no GcHeader, so the
read 8 bytes before the header pulled in unrelated allocator metadata and
dispatched to a random arm.

Detect a registered typed array via lookup_typed_array_kind BEFORE gc_obj_type
(the same pre-check already used for Buffer/Uint8Array, which also lack a
GcHeader) and serialize it in Node's index shape {"0":v,...}. New helpers
stringify_typed_array / stringify_typed_array_pretty are wired into every
buffer-dispatch site (stringify_value, stringify_value_depth, the nested
array-element path, and the replacer/pretty walks). Elements funnel through
write_number, so NaN/Infinity render as null and BigInt views throw Node's
"Do not know how to serialize a BigInt" TypeError. Output matches
node --experimental-strip-types byte-for-byte.

https://claude.ai/code/session_014AH46fwU7BaRRxkMc5Zcq2
@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5c30db1c-3a7c-490d-be23-8b1839140c63

📥 Commits

Reviewing files that changed from the base of the PR and between 5b61919 and c180b3e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • CHANGELOG.md
  • CLAUDE.md
  • Cargo.toml
  • crates/perry-runtime/src/json/mod.rs
  • crates/perry-runtime/src/json/replacer.rs
  • crates/perry-runtime/src/json/stringify.rs

📝 Walkthrough

Walkthrough

Adds stringify_typed_array and stringify_typed_array_pretty serializers that emit typed arrays as Node-compatible {"0":v,...} JSON. Inserts lookup_typed_array_kind detection before gc_obj_type dispatch in five stringify code paths (stringify_value, stringify_value_depth, stringify_array_depth, dispatch_pointer_with_replacer, stringify_value_pretty) to prevent a SIGSEGV. Adds a regression test and bumps the version to 0.5.1165.

Changes

TypedArray JSON.stringify SIGSEGV Fix

Layer / File(s) Summary
Compact and pretty TypedArray serializers
crates/perry-runtime/src/json/stringify.rs
Introduces stringify_typed_array (compact {"0":v,...}) and stringify_typed_array_pretty (indented) emitters using typed-array length/get helpers, delegating per-element number formatting.
Typed-array dispatch before gc_obj_type in all stringify paths
crates/perry-runtime/src/json/stringify.rs, crates/perry-runtime/src/json/replacer.rs
Updates stringify_value, stringify_value_depth, stringify_array_depth, dispatch_pointer_with_replacer, and stringify_value_pretty to call lookup_typed_array_kind and route to the new serializers before falling through to gc_obj_type-based dispatch.
Regression test and ShapeTemplate import
crates/perry-runtime/src/json/mod.rs
Adds stringify_typed_array_emits_node_index_shape test asserting Node-compatible compact and pretty output for populated and empty typed arrays; adds ShapeTemplate to the use crate::stringify import list.
Version bump and changelog
Cargo.toml, CLAUDE.md, CHANGELOG.md
Increments workspace version to 0.5.1165; adds changelog entry describing the fix.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hoppin' through the heap, I found a nasty trap,
A TypedArray would SIGSEGV — oh, what a mishap!
Now I peek with lookup_typed_array_kind first,
Compact and pretty, quenching stringify's thirst.
{"0":2,"1":4,"2":6} — Node agrees, no fuss,
No more segfault crashes on this little bus! 🥕

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description violates explicit repository guidelines by bumping the workspace version in Cargo.toml and editing CLAUDE.md, which the template explicitly states the maintainer handles at merge time. Revert version bumps in Cargo.toml and CLAUDE.md; the maintainer will handle these at merge. Only the implementation changes in json/ files and the new test should remain.
Out of Scope Changes check ⚠️ Warning Version bump changes in Cargo.toml and CLAUDE.md are out of scope per repository guidelines; all other changes (json/ implementation, tests, CHANGELOG) align with the PR's stated fix objective. Remove version bumps from Cargo.toml and CLAUDE.md; these are maintainer responsibilities. Keep all core implementation and test changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing JSON.stringify serialization for TypedArray to prevent SIGSEGV, directly referencing issue #5111.
Linked Issues check ✅ Passed The PR implementation correctly addresses all objectives from #5111: detects TypedArrays before gc_obj_type to prevent SIGSEGV, serializes in Node's index format, includes proper NaN/BigInt handling, and includes comprehensive testing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/issue-5111-ar4t5g

Comment @coderabbitai help to get the list of available commands and usage tips.

@proggeramlug proggeramlug merged commit b17e3ed into main Jun 14, 2026
14 checks passed
@proggeramlug proggeramlug deleted the claude/issue-5111-ar4t5g branch June 14, 2026 07:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TypedArray: map()/subarray() result SIGSEGVs on JSON.stringify, corrupts under Array.from/spread (slice/filter OK)

2 participants