fix(mir): extend chain-sibling drop compensator to match-hop and tuple-chain escapes#2386
Merged
Merged
Conversation
A return alias chain whose intermediate hop is destructured via `match`
(`let mid = o.mid; let leaf = match mid { Mid { leaf, x: _ } => leaf };
leaf`) double-freed the returned subtree: the destructure lowers to a
field load off the scrutinee copy, so the match-bound binder was
invisible to the composite-drop provers' Move-only alias forward-walk.
The owner stayed admitted and its RecordInPlace drop re-freed the
strings the returned value still owns (`free_cstring: C-string header
sentinel missing` abort / SIGSEGV under Guard Malloc). Same failure
through the tuple prover for the tuple twin.
Add a gated interior descent (`descend_match_bound_hop_aliases`): a
RecordFieldLoad/TupleFieldLoad off a tracked alias carrier attributes
the dest to the same owner root iff the dest is a byte-copy inline
aggregate (retained-string and handle-transfer dests stay real owners).
The descended binders feed the record and tuple provers' escape arms
only — never the release-owner Defect-1 blanket, which would newly
exclude owners in clean non-escaping match shapes — so exclusion widens
exactly when the binder leaves the function. Fail-closed: the owner's
non-escaped siblings leak; nothing double-frees.
Regression oracles pin both twins under the poisoned allocator.
Fixes #2384
…oppable A multi-hop tuple-return alias chain (`let mid = o.0; let leaf = mid.0; leaf`) leaked four strings per call through two gaps the record path had already closed: - The multi-hop chain-sibling compensator only walked record roots, so when the tuple composite prover excluded the owner for a >=2-hop escape, nothing discharged the owned siblings along the chain — the intermediate `mid.1` and the outer `o.1` leaked every frame. Generalize the walk to record AND tuple candidate roots, addressing each level with the selector matching the node's own type (`FieldAddr::Tuple` on tuple nodes, `FieldAddr::Record` otherwise). - The tuple prover counted the spliced `hew_string_drop` for a `string` `TupleFieldLoad` read-temp as an element release path, so a caller that merely read the returned pair (`l.0.len()`) tripped the Defect-1 blanket and lost its `TupleInPlace` — both elements leaked. Mirror the record prover's read-temp exemption: the spliced drop balances a codegen-cloned fresh `+1`, not the tuple's original, so it never seeds `release_owner_bases`. Non-string extractions still seed. The compensator's escape triggers stay a strict subset of the provers' exclusion triggers (a discharge only ever lands where the composite drop is already excluded, so the two can never disagree into a double-free); any unmodelled shape still bails the pass and leaks as before. A leak-slope oracle pins the flat slope on the returned-tuple chain. Verified 0 leaks/call under the poisoned-allocator triple at 3 and 50 frames, and no double-free under Guard Malloc across the record, tuple, store, and match-hop escape shapes. Fixes #2383
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.
Summary
I extended the multi-hop chain-sibling drop compensator to two more escape shapes: a
match-bound intermediate alias hop (previously double-freed the intermediate, #2384) and a multi-hop tuple return chain (previously leaked sibling fields, #2383). Both reach exactly-once drop behaviour for the covered shapes. The compensator's escape triggers stay a strict subset of the provers' exclusion triggers, so it never double-frees — a discharge only ever lands where the composite drop is already suppressed.Verification
cargo test -p hew-mir: 879/879 passed.cargo test -p hew-cli --test nested_projection_chain_leak_oracle --release: 20/20 passed.cargo clippy -p hew-mir --all-targets -- -D warnings: clean.cargo fmt --check -p hew-mir -p hew-cli: clean.Out of scope
Both pre-existing, bounded, safe, and tracked as follow-ups — neither is touched or made worse by this change:
stringtuple elements as dischargeable, so a tuple whose elements are user records still leaks unconditionally in the caller. Confirmed identical before and after this change.Fixes #2383, fixes #2384.