Skip to content

rc: a const interface or bound method made over an element read holds a count - #644

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

ASDAlexander77 merged 1 commit into
mainfrom
fix-rc-const-bound-element-read

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

This is the follow-up #642 left for after #641. const m = arr[0].get and const i: I = arr[1] were folded into the view itself and held no reference of their own. Under rc, arr[0] = d then freed the object that m() / i.get() went on to use.

#641 gave storage to a const read out of an element, and #642 did the same for a view made over a field read. A view made over an element read was the case left over. Under rc it now gets storage like a let: readsElement(viewedValue(initial)) joins the rc condition in processConstRef. Under own the folded read stays a borrow.

Tests

  • 00const_view_of_element.ts covers a bound method and an interface view under churn. It is in the default compile/jit lists and in TSLANG_CORPUS (rc + none). On main both cases fail under rc; gc and none pass.
  • Teeth: dropping the new clause fails test-compile-rc-corpus-00const-view-of-element (and its jit twin). Without the switch, it passes.
  • Windows ctest -C Release: 4948/4948. WSL Linux full run: 4930/4930.

🤖 Generated with Claude Code

… a count

`const m = arr[0].get` and `const i: I = arr[1]` were folded into the view
itself, holding no reference of their own, so `arr[0] = d` freed the object
`m()` and `i.get()` then ran on. #641 gave a const read out of an element
storage and #642 gave a view over a field read the same; a view over an
element read is the remaining case. Under rc it now gets storage like a
`let`. Under own the folded read stays a borrow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 6478b38 into main Oct 22, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the fix-rc-const-bound-element-read branch October 22, 2026 20:05
ASDAlexander77 added a commit that referenced this pull request Oct 23, 2026
…global a count (#647)

Two shapes the memory-model fuzzer (#646) found double-freeing under rc
since #639.

- holdGlobalArguments retained the argument right before the call. A
  later argument of the same call could give the global a new value
  first (`f(G, (G = mk(), x))`, `f(H.n, (H.n = mk(), x))`): its release
  freed the block, and the hold then retained and released a freed
  block. The retain (and the #645 unwind slot) now follow the read.
- `const n = G` was folded into the read, holding no count. Once the
  global got a new value, here or in a call, `n` dangled (fuzzer R1).
  #639 made that a crash: `run(n.v)`, with `run` assigning G, held and
  released a field of the freed block. Under rc a const read out of a
  global, or an interface or bound method made over one, now gets
  storage like a const read out of a field or an element (#635, #641,
  #642, #644). 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