Skip to content

Commit 56d1e8e

Browse files
proggeramlugRalph Küpper
andauthored
fix(runtime): arr[Symbol.iterator] read an array's capacity as a class_id (#7563) (#7569)
* fix(runtime): arr[Symbol.iterator] read an array's capacity as a class_id (#7563) ObjectHeader is { object_type: u32, class_id: u32, ... } and ArrayHeader is { length: u32, capacity: u32 }, so the two u32s at offset 4 alias: an array pointer read as an ObjectHeader reports its capacity as a class_id. arr[Symbol.iterator] resolves through js_class_method_bind(arr, "values"), and that builder's receiver->class step, class_id_from_method_receiver, read the field with a bare (*obj).class_id -- guarded against closures and the handle band, but never against the allocation's actual type. So whenever the class whose id equalled the array's capacity owned a method named `values`, the array's iterator resolved to THAT class's method. When it was the calling class, `values` re-entered `values` until the stack guard page: EXC_BAD_ACCESS at `str xzr, [sp], #-0x50`, ~26 000 frames deep. Reported as a `class X extends Map` values() override bug, but Map is incidental and so is the iteration -- the crash reproduces with no Map in the program and no for-of on the path: class Plain { values() { return [777][Symbol.iterator](); } } new Plain().values(); // SIGSEGV Use js_object_get_class_id, the guarded accessor that already existed for this read: it rejects the handle band, the std::alloc'd Map/Set/Regex headers (no GcHeader to probe), and any allocation whose GcHeader.obj_type is not GC_TYPE_OBJECT. The sibling symbol-method arm in native_call_method.rs already routed through it and was never affected -- verified, not assumed. Not #7561: rewrite_collection_view_for_of declines a subclass receiver exactly as documented, and the offending line predates it by hundreds of commits (traces through #5631's file split to #4630), matching the report that it reproduces at 969b447. Coverage: test-files/test_gap_7563_array_iterator_class_id_confusion.ts (byte-compared against node; SIGSEGVs at the parent commit) and object::tests::array_receiver_is_never_read_as_a_class_id (fails with Some(16), the array's capacity, before the fix). * chore: bump version --------- Co-authored-by: Ralph Küpper <ralph@skelpo.com>
1 parent b5a2954 commit 56d1e8e

7 files changed

Lines changed: 416 additions & 80 deletions

File tree

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
88

99
Perry is a native TypeScript compiler written in Rust that compiles TypeScript source code directly to native executables. It uses SWC for TypeScript parsing and LLVM for code generation.
1010

11-
**Current Version:** 0.5.1321
11+
**Current Version:** 0.5.1322
1212

1313

1414
## TypeScript Parity Status

0 commit comments

Comments
 (0)