fix(adapter): detect resources in option/result/variant/fixed-list aggregates (LS-A-23, UCA-A-16)#262
Conversation
…ist aggregates (UCA-A-16)
`element_inner_resources` detected resource handles (own<R>/borrow<R>)
nested in Record/Tuple/Type but its catch-all `_ => {}` swallowed
Option/Result/Variant/FixedSizeList, while its sibling
`element_inner_pointers` recursed into all of them. A `borrow<R>` inside
`list<option<borrow<R>>>` / `list<result<borrow<R>,E>>` /
`list<variant{..(borrow<R>)}>` / `list<fixedlist<own<R>,N>>` was never
detected, so the FACT adapter bulk-copied the raw handle integer across
the instance boundary with no borrow→rep translation —
wrong-resource / use-after-free / type confusion (H-11.5 / UCA-A-16).
Mirror the InnerPointer discriminant-guard mechanism across three layers:
- resolver.rs: add `guards: Vec<DiscriminantGuard>` to `InnerResource`
plus an `unconditional(..)` constructor (empty guards), matching
`InnerPointer`.
- parser.rs: `element_inner_resources` gains an `outer_guards` param and
Option/Result/Variant/FixedSizeList arms that recurse exactly as
`element_inner_pointers` (same disc_size, align_up payload offset, and
per-case DiscriminantGuard chain). Record/Tuple/Type now thread
`outer_guards` through. Added `type_contains_resources` (mirror of
`type_contains_pointers`) to prune handle-free cases.
- adapter/mod.rs + fact.rs: `inner_resource_fixups` is now a struct
(`InnerResourceFixup`) carrying the guard chain; both per-element
borrow→rep emit loops AND-evaluate the chain via a new
`emit_inner_resource_guard_chain` helper before firing the conversion
(empty chain = unconditional, preserving Record/Tuple behavior). This
prevents translating an inactive None/wrong-case slot.
Tests: API-level matrix asserting Elements + inner_resources count and
correct guards for each aggregate shape, plus regressions
(list<record{borrow}>> unconditional, pointer path unchanged, pure-scalar
payloads emit nothing). Non-vacuity verified: the four detection tests
fail (Bulk, count 0) when the new arms are disabled.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Mythos clean-room delta-pass — Tier-5 (parser.rs, resolver.rs, adapter/fact.rs, adapter/mod.rs)VERDICT: NO PROVABLE FINDING. Primary risk (guard fires on wrong/inactive case → silent handle corruption) disproven at the wasm-byte level.
Suites (exit 0): lib 351, adapter_safety 13, wit_bindgen_runtime 73. |
Mythos delta-pass requiredThis PR modifies one or more Tier-5 source files (per Before merge, run the Mythos discover protocol on the
Why this gate exists: LS-A-10 The gate check on this PR will pass once the label is |
LS-N verification gate
Approved Failed LS entries(none) Missing regression tests
Updated automatically by |
Mythos delta-pass (auto)✅ NO FINDINGS across 4 Tier-5 file(s)
Auto-run via |
Found by a Mythos discovery pass on
parser.rs. Closes the still-open arms of the documented hazard UCA-A-16 / H-11.5.Bug
element_inner_resources(populatingCopyLayout::Elements.inner_resourcesfor the FACT adapter's per-elementborrow<R>→rep translation) detected resources in Record/Tuple/Type but its catch-all_ => {}swallowed Option/Result/Variant/FixedSizeList — while the siblingelement_inner_pointersrecursed into all of them. So aborrow<R>insidelist<option<borrow<R>>>(etc.) was undetected and the adapter bulk-copied the raw caller handle index into callee memory instead of translating it → wrong-resource / use-after-free / type confusion. Same "parallel walkers drifted" root cause as LS-P-12 / LS-R-15.Fix (mirrors the working InnerPointer guard mechanism)
InnerResourcegainsguards: Vec<DiscriminantGuard>+unconditionalctor.element_inner_resourcesgains anouter_guardsparam and Option/Result/Variant/FixedSizeList arms identical toelement_inner_pointers(same disc_size,align_uppayload offset, per-case guard values), gated by a newtype_contains_resources.emit_inner_resource_guard_chainso the handle is translated only when the live discriminant selects its case (empty chain = unconditional, preserving Record/Tuple).own<R>stays skipped.Verification
result<borrow,borrow>→ mutually-exclusive guards), and own-not-translated all verified. Full report next comment. Carried caveat: no two-component runtime fixture (behaviour inferred from byte-identity to the runtime-validated pointer path).Tier-5
parser.rs+resolver.rs+adapter/{fact,mod}.rs→ Mythos pass done,mythos-pass-doneapplied.🤖 Generated with Claude Code