Skip to content

translator: accepts [method]/[static] case-folded name collisions CM validation requires rejecting (inherited wasmparser gap) #238

Open

Description

@lannbot

Summary

The translator accepts components that Component Model validation requires
rejecting: two [method] (or [static]) extern names in one scope that are
identical after case-folding, e.g. [method]r.a-b + [method]r.a-B.
Explainer.md §Name Uniqueness defines strongly-unique as lowercase-the-acronyms
→ strip the [...] prefix → compare, and its example list explicitly calls
adding [method]foo.BAR next to [method]foo.bar "a validation error";
Binary.md:280-283 applies strongly-unique to all instance/component
import/export names. Our translator inherits a wasmparser gap and validates
such components, so they flow through to the runtime, where the conventions
layer silently routes both members to the same JS name (the unguarded
methods/statics paths of #185). Per the parity policy (docs/architecture.md
§1: spec is the semantic tie-breaker, wasmtime corroborating — never the
other way), wasmtime agreeing with wasmparser here does not make it correct.

Root cause (upstream)

wasmparser folds case for plain labels — KebabStr's Eq/Hash compare
to_ascii_lowercase() — but ResourceFunc (the a.b payload of
method/static names) derives Eq/Hash/Ord on the raw string
(src/validator/names.rs; identical in 0.251/0.252/0.256). So plain-label
and record-field folded collisions are rejected, method/static ones are not.

Recorded in upstream-component-model-repo-findings.md §Out of scope as a
candidate bytecodealliance/wasm-tools issue (filing is the operator's call).
wit-parser's text parser checks none of this either, so the invalid pair is
reachable from WIT source, not just hand-written WAT:

interface i {
  resource r {
    a-b: func();
    a-B: func();
  }
}

Evidence (2026-08-22, wasm-tools 1.247 / wasmtime 47 / translator-shim @ wasmparser 0.252)

probe (same scope) wasm-tools validate wasmtime compile our translator
instance exports a-b + a-B reject reject reject ([validation])
record fields a-b + a-B reject — reject
[method]r.a-b + [method]r.a-B accept accept accept (plan produced)

Repro for row 3:

(component
  (import "test:i/i" (instance
    (export "r" (type $r (sub resource)))
    (export "[method]r.a-b" (func (param "self" (borrow $r))))
    (export "[method]r.a-B" (func (param "self" (borrow $r))))
  ))
)

deno run --allow-read --allow-write tools/translate/main.ts <that>.wasm
produces a plan; it should fail with a phase: "validation" error.

Suggested fix

Add our own strongly-unique enforcement for [method]/[static] extern
names in translator-shim, after wasmparser validation (walk every
instance-type/component-type scope; fold per Explainer.md §Name Uniqueness;
report through the existing phase: "validation" error taxonomy,
crates/translator-shim/src/error.rs:6-9). Scope it to exactly the wasmparser
gap — plain labels and record/flag/variant/enum labels are already covered —
and remove it when upstream ResourceFunc folds case (upstream-tracking).

Relation to #185

Complementary, not overlapping: #185 extends the conventions-layer
NameCollisionError guards, which are still required for spec-valid
collisions (is-XML vs is-x-m-l both camelCase to isXML — validation
correctly accepts those, only the casing layer can refuse). This issue
restores validation parity so spec-invalid components stop reaching the
runtime at all. Validation record:
#185 (comment)

Provenance

Found validating #185 against the spec and wasmtime/wasm-tools (2026-08-22).
Audit/testing regime: #175. Tracker entry: PR #237.

Activity

  1. added
    bugSomething isn't working
    p1Correctness bugs likely to impact consumers; high-priority missing features
    spec-divergenceBehavior diverges from the pinned CM reference; fix or adjudicate as a named divergence
    upstream-trackingBlocked on or watching an external project (spec, wasmtime, engines, toolchains)
    on Aug 23, 2026
  2. lannbot commented on Aug 25, 2026

    @lannbot
    CollaboratorAuthor

    Upstream search + scope extension (2026-08-25)

    No existing issue covers this divergence in bytecodealliance/wasm-tools or
    bytecodealliance/wasmtime (searched: strongly-unique / case-insensitive /
    uniqueness / kebab / acronym / casing variants, plus PR history of
    crates/wasmparser/src/validator/names.rs). wasm-tools main still carries
    the raw-string derives. Nearest miss: wasm-tools#2138 implemented the
    l vs [*]l.l rule (CM#494) but did not touch case-folding.

    Scope extension — interface names have the same gap. InterfaceName
    derives Eq/Hash/Ord on the raw string exactly like ResourceFunc, so

    (component
      (import "test:i/x-y" (instance))
      (import "test:i/x-Y" (instance))
    )
    

    validates in wasm-tools 1.247, compiles in wasmtime 47, and produces a plan
    through our translator — while the spec folds acronyms in all names before
    comparing. The translator-shim enforcement this issue proposes should cover
    interface names too, not just [method]/[static].

    Spec-side movement, conclusion unchanged. WebAssembly/component-model#703
    (merged 2026-08-18 — after our submodule pin) rewrote strongly-unique as
    canonicalize-then-compare, fixing the non-transitivity reported in CM#702
    (foo = FOO, FOO = [constructor]foo, but foo != [constructor]foo).
    The acronym fold is retained as canonicalization step 1; the invalid-examples
    list now also names [static]foo-BAR.FOO-bar and foo:bar/BAZ. Two
    consequences for the fix here: (a) implement the post-#703 algorithm
    (canonicalize each name, then compare), not the pin's three-rule form — it is
    strictly simpler and transitive; (b) bump the submodule or cite #703 when
    writing the enforcement's spec reference. Note #703 also makes some
    previously-valid pairs invalid (e.g. foo vs [constructor]FOO), which the
    enforcement inherits for free from canonicalize-first.

    CM#118 (open) is adjacent but distinct: it covers spec-valid names colliding
    after language-casing conversion — that is #185's territory, not this issue's.

  3. lannbot commented on Aug 25, 2026

    @lannbot
    CollaboratorAuthor

    Deferred until the wasmtime 49 toolchain bump (operator decision, 2026-08-25)

    CM#703 merged a week ago and upstream is actively reworking this exact corner
    (CM#702 was filed by an implementer); rather than build shim-side enforcement
    that upstream may obsolete within a release cycle, we wait for the wasmtime 49
    / wasmparser bump and re-verify then.

    At revisit:

    1. Check whether the wasmparser that wasmtime-environ 49 links folds case per
      post-#703 strongly-unique (ResourceFunc and InterfaceName in
      validator/names.rs, or probe: [method]r.a-b+[method]r.a-B and
      test:i/x-y+test:i/x-Y — repros in this issue and the tracker entry).
    2. If fixed: the routine toolchain bump closes this; delete the tracker's
      candidate-upstream-issue entry.
    3. If not fixed: implement the shim-side enforcement as specced above
      (post-#703 canonicalize-then-compare), and the upstream filing question
      goes back to the operator.

    Caveat noted for the bet: wasm-tools main still had the raw derives as of
    2026-08-25, so a 49-cycle fix is plausible but not guaranteed.

  4. added
    p2Minor bugs; desirable lower-priority features
    and removed
    p1Correctness bugs likely to impact consumers; high-priority missing features
    on Aug 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingp2Minor bugs; desirable lower-priority featuresspec-divergenceBehavior diverges from the pinned CM reference; fix or adjudicate as a named divergenceupstream-trackingBlocked on or watching an external project (spec, wasmtime, engines, toolchains)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions