Skip to content

rc: a const read out of a field keeps a count of its own - #635

Merged
ASDAlexander77 merged 1 commit into
mainfrom
fix-rc-const-field-read
Oct 22, 2026
Merged

ASDAlexander77 merged 1 commit into
mainfrom
fix-rc-const-field-read

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Under -mm=rc, const c = h.c; h.c = new C(9); print(c.x) read a freed block. A const was folded into the field read itself and held no reference, so the overwrite freed what c still read. The same happened when a return inside try went through a finally that read the const after the field was overwritten.

Fix: under rc, a const whose initializer is a read out of a field (through casts) now gets storage like a let, the same treatment #454 gave a const read out of a local's slot (processConstRef, MLIRGenImpl.h). Under own the folded read stays a borrow, which own already rejects when it is used after the overwrite. own IR and gc/none output don't change.

Not covered yet: element reads (const c = arr[0]). A destructuring past the end of an array (const [a, b, c] = pair, in 00array_rest_copy) reads whatever follows the array's data. A count taken of that faults, and it already does today for a let under rc. Element reads need that out-of-bounds read fixed first.

Test: tests/00const_field_read.ts covers a field, a nullable field, and a read in finally after the overwrite. It runs as a default test and in the rc/none corpus. Teeth: with the new clause switched off, test-compile-rc-corpus-00const-field-read fails.

  • Windows: ctest -C Release, 4862/4862 passed
  • WSL (Linux): 4844/4844 passed

🤖 Generated with Claude Code

`const c = h.c` was folded into the read itself, holding no reference, so
`h.c = d` freed the block `c` still read (and a `return` through `finally`
read it after the field's overwrite). Under rc such a const now gets
storage like a `let`, as a const read out of a local's slot already does
(#454). Under own the folded read stays a borrow, rejected when used after
the overwrite.

Element reads are not covered yet: a destructuring past the end of an
array reads whatever follows its data, and a count taken of that faults,
as it does for a `let` today (00array_rest_copy).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit fbec7e4 into main Oct 22, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the fix-rc-const-field-read branch October 22, 2026 15:45
ASDAlexander77 added a commit that referenced this pull request Oct 22, 2026
`const c = arr[0]` (and `const [c] = arr`) was folded into the read itself,
holding no reference, so `arr[0] = d` freed the block `c` still read. Under
rc such a const now gets storage like a `let`, as a const read out of a
field already does (#635).

That needed an out-of-bounds destructuring fixed first: `const [a, b, c] =
pair` read whatever followed the array's data. Under rc a count taken of it
faulted (for a `let` too), and under gc/none it was undefined behaviour that
LLVM used - `print(c == null)` after it made main print nothing at all. An
element past the end of an array is now the default of its type: null for a
reference (TS has undefined there), 0 for a number. A runtime array checks
its length; a const array literal's size is known, so no read is emitted.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
ASDAlexander77 added a commit that referenced this pull request Oct 22, 2026
…count (#642)

`const m = h.v.get` and `const i: I = h.v` were folded into the view
itself, holding no reference of their own, so `h.v = d` freed the object
`m()` and `i.get()` then ran on (a crash under rc; `let m = h.v.get` was
fine). #637 gave such a const storage when its object is read out of a
local's slot, and #640 made a kept bound method count its object; a view
over a field read was left out. Under rc it now gets storage like a `let`,
as a const read out of a field already does (#635). Under own the folded
read stays a borrow.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant