Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(adapter): detect resources in option/result/variant/fixed-list aggregates (LS-A-23, UCA-A-16)#262

Merged
avrabe merged 2 commits into
mainfrom
fix/uca-a16-resource-in-aggregate
Jun 13, 2026
Merged

fix(adapter): detect resources in option/result/variant/fixed-list aggregates (LS-A-23, UCA-A-16)#262
avrabe merged 2 commits into
mainfrom
fix/uca-a16-resource-in-aggregate

Conversation

@avrabe

@avrabe avrabe commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

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 (populating CopyLayout::Elements.inner_resources for the FACT adapter's per-element borrow<R>→rep translation) detected resources in Record/Tuple/Type but its catch-all _ => {} swallowed Option/Result/Variant/FixedSizeList — while the sibling element_inner_pointers recursed into all of them. So a borrow<R> inside list<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)

  • InnerResource gains guards: Vec<DiscriminantGuard> + unconditional ctor.
  • element_inner_resources gains an outer_guards param and Option/Result/Variant/FixedSizeList arms identical to element_inner_pointers (same disc_size, align_up payload offset, per-case guard values), gated by a new type_contains_resources.
  • The adapter wraps each borrow→rep conversion in emit_inner_resource_guard_chain so the handle is translated only when the live discriminant selects its case (empty chain = unconditional, preserving Record/Tuple). own<R> stays skipped.

Verification

  • 7 parser tests: resource in option/result/variant/fixed-list detected with correct guard values; Record stays unconditional; pointer path unchanged. Non-vacuity proven (routing the 4 kinds back to the swallow makes the detection tests fail). Workspace lib 351 + adapter_safety 13 + wit_bindgen_runtime 73 (incl. resource_borrow / resource_borrow_in_record / resource_import_and_export) green via exit code; clippy/fmt clean.
  • Mythos clean-room pass: NO PROVABLE FINDING — the resource guard emission is proven byte-identical to the already-runtime-validated InnerPointer guard path (disc load width/offset/compare/AND-chain), so it fires exactly on the live case; payload offsets, nested threading (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-done applied.

🤖 Generated with Claude Code

avrabe and others added 2 commits June 13, 2026 19:23
…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]>
@avrabe

avrabe commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

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.

  • Guard value/width/offset (hunted hardest)emit_inner_resource_guard_chain diffed line-by-line against the pointer path's guard block: same dst_base + loop_idx*element_size base, same MemArg{offset: guard.position, memory: callee}, same width match (1→i32.load8_u, 2→i32.load16_u, else→i32.load), same i32.const value/i32.eq/AND-chain/if. Byte-identical code sections proven via round-trip for option-Some {0,1,1}, variant-case-1, and nested result-Ok+option-Some [{0,0,1},{1,1,1}]. Both resource fixup loops use the same base/element_size/memory as the handle load — no offset divergence.
  • Payload offsetoption<borrow<R>>: disc_size(2)=1, borrow align=4 → payload at align_up(1,4)=4, guard.position=0, byte_size=1; identical to the pointer arm's formula.
  • Nested threadingresult<borrow,borrow> → two InnerResources guards value=0/1 (mutually exclusive); result<option<borrow>> → 2-guard AND-chain (byte-identity proven).
  • own vs borrowown<R> detected in layout but the adapter continues on is_owned before pushing a fixup; never translated; unchanged.
  • Regression — pointer guard emission byte-identical to itself; Record/Tuple resources emit empty guards → no if wrapper; all resource runtime suites green.

Suites (exit 0): lib 351, adapter_safety 13, wit_bindgen_runtime 73.
Caveat: no two-component wasmtime fixture through list<option<borrow<R>>> — Risk-1 proof is at the wasm-emission level (byte-identity to the runtime-validated pointer path) rather than executed end-to-end.

@avrabe avrabe added the mythos-pass-done Mythos delta-pass completed on Tier-5 file changes; findings (or NO FINDINGS) attached to PR label Jun 13, 2026
@avrabe avrabe enabled auto-merge (squash) June 13, 2026 17:41
@github-actions

Copy link
Copy Markdown

Mythos delta-pass required

This PR modifies one or more Tier-5 source files (per
scripts/mythos/rank.md):

meld-core/src/adapter/fact.rs
meld-core/src/adapter/mod.rs
meld-core/src/parser.rs
meld-core/src/resolver.rs

Before merge, run the Mythos discover protocol on the
modified Tier-5 files:

  1. Follow scripts/mythos/discover.md
    — one fresh agent session per touched Tier-5 file.
  2. For each finding, the agent must produce both a Kani
    harness and a failing PoC test (per the protocol's
    "if you cannot produce both, do not report" rule).
  3. Attach a comment on this PR with either the findings
    (formatted per discover.md's output schema) or
    NO FINDINGS.
  4. Add the mythos-pass-done label to this PR.

Why this gate exists: LS-A-10
(CABI alignment padding in async-lift retptr writeback) was
found by the v0.8.0 pre-release Mythos pass — but it had
lived in the callback emitter since #128, across six
releases. A PR-time gate would have caught it at review
time instead of at the release boundary.

The gate check on this PR will pass once the label is
applied.

@github-actions

Copy link
Copy Markdown

LS-N verification gate

⚠️ 45/51 verified — 6 missing regression tests

count
Passed (≥1 test, all green) 45
Failed (≥1 test failure) 0
Missing (no ls_*_NN_* test found) 6

Approved loss-scenarios.yaml entries are expected to have a
regression test named ls_<letter>_<num>_* (e.g. LS-A-11
ls_a_11_*). The gate runs each prefix via cargo test --lib --no-fail-fast and aggregates pass/fail/missing.

Failed LS entries

(none)

Missing regression tests
  • LS-P-20
  • LS-R-15
  • LS-A-21
  • LS-A-22
  • LS-A-23
  • LS-M-8

Updated automatically by tools/post_verification_comment.py.
Source of truth: safety/stpa/loss-scenarios.yaml.

@avrabe avrabe merged commit 667a8f5 into main Jun 13, 2026
16 of 20 checks passed
@avrabe avrabe deleted the fix/uca-a16-resource-in-aggregate branch June 13, 2026 17:51
@github-actions

Copy link
Copy Markdown

Mythos delta-pass (auto)

NO FINDINGS across 4 Tier-5 file(s)

File Verdict Hypothesis
`` ✅ NO FINDINGS
`` ✅ NO FINDINGS
`` ✅ NO FINDINGS
`` ✅ NO FINDINGS

Auto-run via anthropics/claude-code-action@v1
(SHA-pinned) on the touched Tier-5 files, using the
maintainer's Max-plan OAuth token. See
.github/workflows/mythos-auto.yml and
scripts/mythos/discover.md.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mythos-pass-done Mythos delta-pass completed on Tier-5 file changes; findings (or NO FINDINGS) attached to PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant