Skip to content

Don't generate a bare "$" from an empty export name - #2832

Merged
sbc100 merged 2 commits into
WebAssembly:mainfrom
Nishuuzz:fix/empty-export-name-identifier
Aug 21, 2026
Merged

Don't generate a bare "$" from an empty export name#2832
sbc100 merged 2 commits into
WebAssembly:mainfrom
Nishuuzz:fix/empty-export-name-identifier

Conversation

@Nishuuzz

Copy link
Copy Markdown
Contributor

wasm2wat --generate-names produces output it can't read back when a module has an export with an empty name.

(module (func $f) (export "" (func $f)))

Disassembled with --generate-names:

(func $ (type $t0))
(export "" (func $))

and assembling that back gives error: empty identifier.

Generated names are derived from import and export names, built as "$" followed by the name, so an empty export name leaves just the sigil. This skips an empty name instead, and the item keeps whatever name the rest of the pass gives it — another of its export names if it has one, otherwise the index-based name it would have had anyway.

Empty export names are legal and do turn up: test/wasm2c/export-names.txt already has one, which is where I hit this.

Imports go through the same helper but can't reach it, because the name there is always module_name + "." + field_name and so is never empty. I put the check in the shared helper anyway rather than in the export path, since it's guarding a property of the generated identifier rather than anything specific to exports.

How I found it

Same round-trip sweep as #2830, extended to the writer variants rather than just the default one: for every module in test/, disassemble with --fold-exprs, --inline-exports, --inline-imports, --generate-names and --no-debug-names in turn, then assemble the result again. --generate-names was 1105 of 1106, and this was the one failure. It is 1106 now.

Testing

test/roundtrip/generate-empty-export-name.txt covers a func whose only export name is empty, alongside one with a usable export name so both paths are visible in the output. It fails without the change with the empty identifier error above.

Note it deliberately does not pass --debug-names: with a name section present the original names survive and the generator never runs, so the test wouldn't exercise this at all.

roundtrip goes from 93 to 94, and desugar, typecheck, parse and the unit tests are unchanged.

Unrelated, while I was in there

The same sweep found --fold-exprs output failing to re-assemble for code metadata annotations and for branch hints:

test/dump/code-metadata.txt          error: unexpected token "metadata.code.test", expected an instr.
test/parse/branch-hints.txt          error: unexpected token (, expected ).

That looks like a separate problem in how annotations are placed in folded output, so I've left it out of this PR. Happy to open an issue for it if it isn't already known.

--generate-names derives names from import and export names, and builds
them as "$" followed by the name. An empty export name therefore produces
just "$", which is not a valid identifier, so wasm2wat emits output it
cannot read back:

  (func $ (type $t0))
  (export "" (func $))

  error: empty identifier.

Skip an empty name so the item keeps whatever name it gets from the rest
of the pass: another export name if it has one, otherwise the index-based
name that would have been used anyway.
wasm2c derives its C identifiers from the same generated names, so the
func that used to be named "$" is now named after the export it does
have. Its C symbol changes from w2c_test__0 to w2c_test_0x2A0x2F_0.
@sbc100
sbc100 merged commit 2e9af63 into WebAssembly:main Aug 21, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants