fix: Mythos v0.4 follow-up — items 4, 5, 6 (closes #112 partially)#117
Merged
Conversation
#112) Items 4, 5, and 6 from the v0.4 Mythos pre-release pass: three HashMap-iteration leaks in meld-core/src/resolver.rs that all silently corrupted fusion output by changing across builds. 1. Item 4 (LS-CP-3): graph.adapter_sites was populated by iterating graph.resolved_imports (a HashMap) and never sorted. Rust's default hasher randomises per-process, so the push order of cross-component sites varied across builds. Downstream: * lib.rs:413-414 allocates merged function indices as adapter_base + adapter_offset, so a different push order yields different merged indices for the same logical adapters. * merger.rs:1500 walks adapter_sites and takes the first match for an (import_name, import_module) pair, so when two sites share that pair the merged module routes calls to whichever was pushed first. The 0.3.0 fix sorted reexporter_components / reexporter_resources but missed adapter_sites itself. Fix: extract sort_adapter_sites_for_determinism, call it after both identify_adapter_sites and identify_intra_component_adapter_sites complete. Sort key is the totally-ordered tuple (from_component, from_module, import_module, import_name, to_component, to_module, export_name, export_func_idx). 2. Item 5 (LS-R-10 / UCA-R-3): identify_intra_component_adapter_sites set import_module = res.import_name (the field name) when promoting a ModuleResolution to an AdapterSite. This dropped the from_import_module disambiguator, which ModuleResolution carries precisely so the resolver and merger can tell apart same-name imports from different modules (e.g. env.alloc vs mylib.alloc, or wasi:clocks/wall-clock@0.2.0::now vs wasi:clocks/monotonic-clock@0.2.0::now). merger.rs:1500's disjunctive match (imp.module == site.import_module || imp.name == site.import_module) then accepts EITHER core import for EITHER promoted adapter site when the disambiguator is wrongly set to the field name, collapsing two distinct calls onto whichever site sat first in adapter_sites. Fix: use res.from_import_module when non-empty; fall back to res.import_name only for legacy synthesised resolutions where from_import_module is empty. 3. Item 6 (LS-CP-3, second class): three caller_lower_map.iter().next() / lower_map.iter().next() encoding fallbacks selected an arbitrary string_encoding (UTF-8 vs UTF-16) when name-based matching missed. Same root cause as item 4 — HashMap iteration randomises across builds, so the chosen encoding and the string_transcoding flag could flip silently from build to build. Fix: replace each iter().next() with iter().min_by_key(|(k, _)| **k) so the smallest-keyed entry is picked deterministically. Oracle pairs: * Unit test resolver::tests::test_issue112_item5_intra_adapter_preserves_from_import_module: constructs a hand-built ParsedComponent with two ModuleResolutions sharing import_name = "f" but different from_import_module's ("providerA"/"providerB"), populates core_entity_order so build_entity_provenance produces the func_source entries needed for promotion to fire, calls identify_intra_component_adapter_sites directly, asserts each promoted site's import_module equals its from_import_module rather than "f". Verified to fail pre-fix. * Unit test resolver::tests::test_issue112_item4_sort_adapter_sites_is_canonical: asserts sort_adapter_sites_for_determinism is a canonical permutation invariant and idempotent over three input orderings. * Integration test tests/issue_112_mythos_v04.rs (two tests): * issue112_item5_intra_component_same_name_different_module — full pipeline with two providers, asserts run() returns 21 (= 1 + 2*10) rather than 11 or 22 (the wrong-routing values). * issue112_item4_adapter_sites_determinism — fuses the same input five times in fresh Fuser instances, asserts byte-equal output. * Kani harnesses kani_proofs::check_item4_sort_is_canonical_under_swap and check_item5_promotion_preserves_from_import_module: model the sort and promotion logic abstractly, prove the determinism and field-preservation properties under bounded inputs. LS entries: LS-R-10 (UCA-R-3, intra-adapter import_module) and LS-CP-3 (SR-19 / H-7, HashMap iteration leakage in adapter_sites + encoding fallbacks) added to safety/stpa/loss-scenarios.yaml, both approved / high priority. 73-test wit_bindgen_runtime suite stays green; full meld-core test suite (179 lib tests + integration tests) green. Closes #112 (items 4, 5, 6). Items 1-3 (HT_CAPACITY enforcement, u32 truncation in table_base_addr, silent memory.maximum raise) deferred — they need adversarial fixtures meld doesn't currently accept and the oracle bar can't be met within the v0.4 follow-up window. Disposition posted as a comment on #112. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fc4409f to
010f6a4
Compare
avrabe
added a commit
that referenced
this pull request
Apr 29, 2026
V&V-hardening minor release. Closes 5 issues: - #98 — semver-correct compare_version (PR #113) - #99 — resource-import fallback name-keyed, sentinel eliminated (PR #115) - #102 — Kani + proptest harnesses for parser/merger/resolver (PR #116) - #104 — cargo-fuzz scaffolding with 4 targets (PR #114) - #112 — Mythos v0.4 follow-up: items 4, 5, 6 confirmed and fixed (PR #117) New approved STPA loss scenarios: LS-R-10, LS-CP-3. Pre-release Mythos delta pass (tier-5 + tier-4 changed since v0.3.0): merger.rs and resolver.rs scanned; **no confirmed findings**. The cargo-fuzz scaffolding immediately surfaced a real parser panic on truncated component-section input — tracked as #118 for v0.4.1 / v0.5. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
graph.adapter_siteswas populated by iteratinggraph.resolved_imports(aHashMap) and never sorted. Fixed by extractingsort_adapter_sites_for_determinismand calling it after the cross- and intra-component promotion passes.identify_intra_component_adapter_siteswas settingimport_module = res.import_name, dropping thefrom_import_moduledisambiguator and causingmerger.rs:1500's disjunctive match to route same-name-different-module imports to the wrong upstream export. Fixed by preservingfrom_import_modulewhen non-empty.caller_lower_map.iter().next()/lower_map.iter().next()encoding fallbacks picked an arbitrarystring_encodingfrom aHashMap, silently flipping UTF-8/UTF-16 across builds. Fixed by switching tomin_by_key(|(k, _)| **k).Items 1–3 (HT_CAPACITY enforcement, u32 truncation in
table_base_addr, silentmemory.maximumraise) are deferred — they need adversarial fixtures meld doesn't currently accept and the oracle bar can't be met within the v0.4 follow-up window. Disposition will be posted as a comment on #112.Closes #112 partially. Links #112.
Oracle pairs
Each fixed item ships the v0.3.0 oracle pattern (Kani harness + PoC test):
meld-core::resolver::tests::test_issue112_item4_sort_adapter_sites_is_canonical— assertssort_adapter_sites_for_determinismis a canonical permutation invariant and idempotent.meld-core::resolver::tests::test_issue112_item5_intra_adapter_preserves_from_import_module— hand-builds aParsedComponentwith twoModuleResolutionssharingimport_name = "f"but differentfrom_import_modules, callsidentify_intra_component_adapter_sitesdirectly, asserts each promoted site'simport_moduleequals itsfrom_import_module. Verified to fail pre-fix.tests/issue_112_mythos_v04.rs::issue112_item5_intra_component_same_name_different_module— full-pipeline integration test: two-provider component, assertsrun()returns 21 (= 1 + 2 * 10) rather than 11 / 22 (the wrong-routing values).tests/issue_112_mythos_v04.rs::issue112_item4_adapter_sites_determinism— fuses the same input five times in freshFusers and asserts byte-equal output.kani_proofs::check_item4_sort_is_canonical_under_swapandcheck_item5_promotion_preserves_from_import_modulemodel the sort and promotion logic and prove the determinism and field-preservation properties under bounded inputs.STPA loss scenarios
Two new approved entries in
safety/stpa/loss-scenarios.yaml:from_import_moduledisambiguator.adapter_sitesorder andcaller_encodingfallback.Both modeled on LS-P-4 / LS-A-8 from commit
dc50c28.Test plan
cargo test --package meld-core— full meld-core suite (179 lib tests + 73 wit_bindgen_runtime + integration tests) greencargo test --workspace— all crates greencargo fmt --all --check— cleancargo clippy --package meld-core --all-targets -- -D warnings— clean🤖 Generated with Claude Code