Version
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 6.0.6 (ce75e06)
clang version 24.0.0git (llvm-project ff6d537b14d737719d6377789784d04ff9565f65)
Target: wasm32-unknown-emscripten
Installed via emsdk "latest" on Linux x86_64 (Devuan).
Problem
Building with -sSINGLE_FILE produces an .html whose embedded wasm fails to
instantiate in Firefox 140 ESR:
CompileError: wasm validation error: at offset 8421340: invalid data initializer-kind field
The same project built without -sSINGLE_FILE produces a .wasm that
wasm-opt --all-features validates and that runs correctly in the same browser.
This emcc version embeds the wasm as a raw JS string literal decoded by:
function binaryDecode(f){for(var b,v=0,n=f.length,t=new Uint8Array(n);v<n;++v)b=f.charCodeAt(v),t[v]=~b>>8&b;return t}
(not base64 as older versions did).
What I found
-
Reference (multi-file) wasm: 15,022,632 bytes, valid.
-
Saving the result of findWasmBinary() from the browser on the single-file
build gives 15,022,633 bytes — one extra byte.
-
Byte-level comparison: a single 0x20 (space) is present at decoded offset
8,417,950 that does not exist in the reference wasm. Every byte before it
is identical; every byte after is identical but shifted by one. The validation
error at offset 8,421,340 is the parser failing on the shifted data a few KB later.
-
The spurious space physically exists in the emitted .html: inside the embedded
string literal, between a literal > character and a \f escape sequence.
The surrounding emitted text (escapes shown as written in the file):
decodes to reference bytes 32 0d 25 3e | 0c 25 33 — the space between >
and \f corresponds to nothing in the reference binary. So this is an
encode-side defect (the emitted string already contains the extra byte),
not a browser/decoding problem.
-
Possibly relevant observation: escaping in the emitted string is inconsistent —
e.g. byte 0x0C appears in some places as a raw control character and in other
places as \f — which may suggest a post-processing pass (HTML/JS
minification?) rewriting whitespace-class characters inside the string literal
after emission.
-
Counter-test: embedding the identical wasm bytes as a base64 data: URI
in the same .html loads and runs perfectly.
-
Size dependence: small programs (hello-world size) built with -sSINGLE_FILE
work fine. Two separate large projects fail the same way: a ~15 MB wasm
(extra byte at 8,417,950) and a ~7.5 MB wasm (validation error at 7,490,125).
Link flags used
-sSINGLE_FILE -sASYNCIFY -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=1073741824
-sEXPORTED_RUNTIME_METHODS=stringToNewUTF8 --shell-file <custom shell> -Oz
The C source is generated by the FreeBASIC compiler's emscripten target
(fbc -target js-asmjs), which drives emcc for compile and link.
Reproduction
Happens consistently for me with multi-MB wasm binaries. The failing .html is
~18 MB — happy to provide it, the matching reference .wasm, and exact byte
offsets on request, or to test candidate fixes / run with EMCC_DEBUG=1.
Version
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 6.0.6 (ce75e06)
clang version 24.0.0git (llvm-project ff6d537b14d737719d6377789784d04ff9565f65)
Target: wasm32-unknown-emscripten
Installed via emsdk "latest" on Linux x86_64 (Devuan).
Problem
Building with
-sSINGLE_FILEproduces an .html whose embedded wasm fails toinstantiate in Firefox 140 ESR:
The same project built without
-sSINGLE_FILEproduces a .wasm thatwasm-opt --all-featuresvalidates and that runs correctly in the same browser.This emcc version embeds the wasm as a raw JS string literal decoded by:
(not base64 as older versions did).
What I found
Reference (multi-file) wasm: 15,022,632 bytes, valid.
Saving the result of
findWasmBinary()from the browser on the single-filebuild gives 15,022,633 bytes — one extra byte.
Byte-level comparison: a single
0x20(space) is present at decoded offset8,417,950 that does not exist in the reference wasm. Every byte before it
is identical; every byte after is identical but shifted by one. The validation
error at offset 8,421,340 is the parser failing on the shifted data a few KB later.
The spurious space physically exists in the emitted .html: inside the embedded
string literal, between a literal
>character and a\fescape sequence.The surrounding emitted text (escapes shown as written in the file):
decodes to reference bytes
32 0d 25 3e | 0c 25 33— the space between>and
\fcorresponds to nothing in the reference binary. So this is anencode-side defect (the emitted string already contains the extra byte),
not a browser/decoding problem.
Possibly relevant observation: escaping in the emitted string is inconsistent —
e.g. byte 0x0C appears in some places as a raw control character and in other
places as
\f— which may suggest a post-processing pass (HTML/JSminification?) rewriting whitespace-class characters inside the string literal
after emission.
Counter-test: embedding the identical wasm bytes as a base64
data:URIin the same .html loads and runs perfectly.
Size dependence: small programs (hello-world size) built with
-sSINGLE_FILEwork fine. Two separate large projects fail the same way: a ~15 MB wasm
(extra byte at 8,417,950) and a ~7.5 MB wasm (validation error at 7,490,125).
Link flags used
The C source is generated by the FreeBASIC compiler's emscripten target
(fbc -target js-asmjs), which drives emcc for compile and link.
Reproduction
Happens consistently for me with multi-MB wasm binaries. The failing .html is
~18 MB — happy to provide it, the matching reference .wasm, and exact byte
offsets on request, or to test candidate fixes / run with EMCC_DEBUG=1.