You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With the startup chain fixed (#8726/#8738/#8739/#8763), the natively-compiled Claude Code cli.js 2.1.112 bundle now boots and enters the agent loop (--help works; -p progresses through hooks / skills attachment / autocompact per --debug-file). But -p then fails non-deterministically during agent-loop init (num_turns: 0), with a different symptom nearly every run — the signature of GC / heap corruption under the app's allocation churn:
TypeError: (number).get is not a function / (number).set is not a function — a Map/object comes back as a number (its header/box clobbered)
TypeError: Cannot read properties of undefined (reading 'def') — a live object read as undefined
SIGSEGV — EXC_BAD_ACCESS, KERN_INVALID_ADDRESS at 0x00000000ff00fff7 (a corrupted/tagged value dereferenced as a raw pointer)
intermittent hangs
Not fixed by GC pacing
12-run probe: default, PERRY_GC_MOVING_LOOP_POLLS=0, and PERRY_GEN_GC=0 all hang/err; both-off gives the .set error + SIGSEGV. No configuration stabilizes it, so it's not a single pacing knob.
Node parity
node cli_2.1.112.js --help and the agent loop run cleanly under Node — this is perry-runtime GC/memory correctness under a large real workload, i.e. the memory-parity frontier (cf. #7019 scavenge parity and the live-sweep fixes), not an app bug.
Next step to pin it
The shipped binary is stripped. Build a PERRY_DEBUG_SYMBOLS=1 cc (invalidates the codegen cache → full ~50 min recodegen + link; needs ~15 GB transient), reproduce the SIGSEGV, and symbolicate the .ips faulting frames to locate the clobbered allocation / missed root. The reduced-repro will likely be a churn pattern in the agent-loop init (skill/hook registries, token counting) rather than a one-liner.
Found while verifying the natively-compiled Claude Code boots end-to-end after the startup-chain fixes.
A marked (live) array holds an UNMARKED typed_array child — the copying-minor evacuating scavenge does NOT mark/evacuate a typed_array value stored in an array element (also seen: object→object and closure→string, but the array→typed_array edge is the consistent first offender; the child lands at the same nursery offset …af430 every run). The unmarked typed_array is then swept, and later a 0xff-poisoned/stale pointer to it is dereferenced — which is exactly the non-deterministic crash family: js_is_truthy + 208 (ldr w8,[x8], x8=0xff00000000) and shape_is_url_search_params + 44 (obj=0xffff00f7), both faulting on freed-then-poisoned memory. This also explains the (number).get/set is not a function runs (the freed object's slot reads back as a small/number-looking value).
Fix locus
crates/perry-runtime/src/gc/copying.rs — the copying-minor scan (scan_object_fields → visit_gc_rewrite_slots → scan_slot → check_bits_with_reason → decode_bits_for_preflight / classify_for_preflight → check_ptr_with_reason). Either the array's layout does not visit the element slot holding the typed_array, or decode_bits_for_preflight/classify_for_preflight returns Ok(None) / a wrong CopyingPointerKind for a young typed_array header, so it is never pushed to the worklist. Not a GC-root-slot corruption (the write/read root-slot trap did NOT fire), and not fixed by PERRY_GC_MOVING_LOOP_POLLS=0.
Repro (deterministic diagnostic)
cd /tmp/ccws && HOME=/tmp/cc_home ANTHROPIC_API_KEY=… PERRY_GC_VERIFY_MARK=1 /tmp/cc-test -p "say PONG" prints the marked->UNMARKED … child=… ctype=typed_array line on every run. Instrument decode_bits_for_preflight/classify_for_preflight for that child header to see why it isn't classified as an evacuable young object; fix the classification/layout so the typed_array element is traced; verify the verifier prints OK (no marked->unmarked) and the 25× -p crash rate drops to ~0.
Closing: the root cause was under-applied call padding on same-module direct calls (#8852, landed via batch #8857 on 2026-08-26), not a GC defect. The natively compiled cli.js now boots and runs the agent loop deterministically (see the #9400 / #9506 work).
Activity
proggeramlug commentedon Aug 24, 2026
Root cause pinned by the mark verifier
Running the
-prepro withPERRY_GC_VERIFY_MARK=1 PERRY_GC_VERIFY_EVACUATION=1 PERRY_GC_NATIVE_SLOT_VERIFY=1fires the mark verifier every run:A marked (live) array holds an UNMARKED typed_array child — the copying-minor evacuating scavenge does NOT mark/evacuate a
typed_arrayvalue stored in an array element (also seen: object→object and closure→string, but the array→typed_array edge is the consistent first offender; the child lands at the same nursery offset…af430every run). The unmarked typed_array is then swept, and later a0xff-poisoned/stale pointer to it is dereferenced — which is exactly the non-deterministic crash family:js_is_truthy + 208(ldr w8,[x8], x8=0xff00000000) andshape_is_url_search_params + 44(obj=0xffff00f7), both faulting on freed-then-poisoned memory. This also explains the(number).get/set is not a functionruns (the freed object's slot reads back as a small/number-looking value).Fix locus
crates/perry-runtime/src/gc/copying.rs— the copying-minor scan (scan_object_fields→visit_gc_rewrite_slots→scan_slot→check_bits_with_reason→decode_bits_for_preflight/classify_for_preflight→check_ptr_with_reason). Either the array's layout does not visit the element slot holding the typed_array, ordecode_bits_for_preflight/classify_for_preflightreturnsOk(None)/ a wrongCopyingPointerKindfor a young typed_array header, so it is never pushed to the worklist. Not a GC-root-slot corruption (the write/read root-slot trap did NOT fire), and not fixed byPERRY_GC_MOVING_LOOP_POLLS=0.Repro (deterministic diagnostic)
cd /tmp/ccws && HOME=/tmp/cc_home ANTHROPIC_API_KEY=… PERRY_GC_VERIFY_MARK=1 /tmp/cc-test -p "say PONG"prints themarked->UNMARKED … child=… ctype=typed_arrayline on every run. Instrumentdecode_bits_for_preflight/classify_for_preflightfor that child header to see why it isn't classified as an evacuable young object; fix the classification/layout so the typed_array element is traced; verify the verifier printsOK (no marked->unmarked)and the 25×-pcrash rate drops to ~0.batch: land #8825, #8826, #8830, #8832 (#8835)
batch: land #8848, #8849, #8850, #8852, #8853 (#8857)
proggeramlug commentedon Sep 2, 2026
Closing: the root cause was under-applied call padding on same-module direct calls (#8852, landed via batch #8857 on 2026-08-26), not a GC defect. The natively compiled cli.js now boots and runs the agent loop deterministically (see the #9400 / #9506 work).