Files
scriptc/packages/compiler/src
Malte Ubl 5133738a83 Return walks of borrowed parameters without a reference
An edge-preserving function whose every return is a walk of its borrowed
parameters (accessors such as `node.children`, `t.types`, parent walks,
or a call to another such function) now returns its result at +0 from the
borrowing body. The result stays reachable from the arguments, so direct
callers that consume it as a receiver, a walk, or a borrowable argument
use it in place; every other direct caller tests the pending exception
and then retains it, before the argument snapshots that keep it reachable
are released. The owned adapter retains a present result (a throwing body
returns a null dummy, which string and array retains do not accept) before
releasing its parameters. Candidates borrow every reference parameter,
have no try statements and return a plain reference (instances, records,
arrays, strings, nullable-pointer unions).

Implementations of a vtable slot that borrows parameters are excluded:
virtual dispatch reaches their borrowing body (or its virtual adapter)
directly and its callers own the result. Without this, corpus 4545's
virtual accessors hit a heap-use-after-free in the sanitized lane.

The set grows to a fixpoint, since a call to a borrowed-return function
with walk arguments is itself a walk; walk facts are then recomputed with
the final set, admitting only parameters whose convention borrows.
Walk locals now cover every plain reference type, not only instances.

In tsc-ts, compareNodes -> sourceFileOf -> getSourceFileOfNode and
maybeTypeOfKind's loop over typesOf(t) no longer touch reference counts.
2026-10-09 15:03:23 -07:00
..