Repository navigation
steins-infer: an object reached through an unresolved alias is escaped, and a write through an unbound name sweeps the escaped objects (#1048) - #1056
Merged
Conversation
5 tasks
zonuexe
force-pushed
the
claude/array-alias-heap-write
branch
from
October 11, 2026 07:32
bae84a7 to
1f55418
Compare
…red to Other, and an expression statement that yields is a barrier (#1048)
…es, and a write through a name the store does not bind sweeps the escaped objects, so an alias read back from an array no longer leaves the original's property fact stale (#1048)
…e helper, under the function-length line (#1048)
…so the common empty case costs one word, and the new helpers stay under the width line (#1048)
…pelled names and yield, and the changelog fragment (#1048)
… which receivers they write a property through, and a yielding statement keeps its kind; a generator records whether it yields by reference (#1048)
…pes reach its fall-through, a property written inside an expression sweeps like a statement-level one, and a yield sweeps the escaped objects while keeping the locals unless the generator yields by reference (#1048)
…ent take the review's rows: embedded writes, forgotten names, loop-body escapes and yields (#1048)
zonuexe
force-pushed
the
claude/array-alias-heap-write
branch
from
October 11, 2026 08:29
1f55418 to
bf1cc70
Compare
zonuexe
marked this pull request as ready for review
October 11, 2026 08:35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1048: an object reached through an unresolved alias kept a stale property fact (unsound).
Root cause
The store followed an object only through a plain
$b = $acopy.apply_prop_assigndid nothing when the receiver was unbound, and an array literal escaped resources but not objects. Further holes with the same root turned up:Opaqueconstructs did not sweep escaped objects.Other(match,(object), computed keys) hid the objects they stored.$r = yield $o;kept$o's facts across the suspension.byref($o->p)to a resolved function keptp.Rule (
crates/steins-infer/src/heap_alias.rs)Reach marks the object escaped. Any of these reaches it:
??, a cast or+;Othervalue (newStmt::unspelled).These routes reach through the ones above: foreach value and by-ref,
list,array_map/array_walk,current/reset/end/array_pop/array_shift,$arr[$k],iterator_to_array,array_values/array_filter, and identity functions.A write through an unbound name sweeps the escape set. That covers:
unset;A by-ref pass of a bound object's property forgets that property.
Constructs.
WalkCx::heap_sweeps).Opaquesweeps.yieldlowers to a barrier.The whole escape set is swept rather than filtered by class or property name. An unbound receiver has no class the walk can trust, and a write can run
__setor a hook. An object that no route reached keeps its facts.Tests
heap_alias.rsholds:unknown), with the related precise cases unchanged;needInt($o->p)false mismatch that is now silent, with a twin that still fires.-D warnings, as doesxtask changelog. The tests for syntax, infer, db and gen also pass.Measurement (ten public packages, base d543c7c)
check,effect-diffand the five transforms: byte-identical.RSS is unchanged; the new field is boxed. The cost is about 2% at most, within noise at load 15–40.
Open (recorded in the ADR amendment)
__toStringthat mutates$thisunder.stays stale.yieldinside a condition or areturnis not covered.Review outcome
Adversarial review, two rounds: approve.
unknownwhere PHP differs.releasevsunbindrebinding (18 shapes), the per-scope escape recorder (nesting, unwind, break/continue),writes_throughcoverage (35 shapes), andyield from/ by-ref closures. None was stale.$this,get_defined_vars, magic or hook writes,__destruct, two aliased entry objects, an inline-called closure as an assignment's right side, and a destructure nested in an assignment.