brintos

brintos / musl public Read only

0
0

wasm32: size_t is unsigned int but clang uses unsigned long — breaks all C++ (operator new signature) #1

Closed alex opened this issue · 1 comment
A alex commented

Summary

On the wasm32 musl port, size_t resolves to unsigned int, but clang for wasm32 defines __SIZE_TYPE__ as unsigned long. Both are 32-bit on wasm32, so the mismatch is binary-compatible and completely invisible to C code — which is why it has gone unnoticed. It is fatal to C++: the language requires operator new's first parameter to be exactly the implementation's built-in size_t, so libc++abi (and any C++ translation unit that declares an allocation function) fails to compile.

Root cause

arch/wasm32/bits/alltypes.h.in starts with:

#define _Addr int

musl derives size_t (and ptrdiff_t, intptr_t, …) from _Addr, so _Addr int makes size_t = unsigned int. Every other arch in the tree whose pointer-width type must match the compiler uses #define _Addr long (x86_64, aarch64, riscv64); wasm32 is the odd one out. Clang's wasm32 target uses unsigned long for __SIZE_TYPE__, so the header and the compiler disagree.

Reproduction

Build any C++ that declares an allocation function (e.g. libc++abi) with the wasm32-hwjs toolchain:

clang: .../libcxxabi/src/stdlib_new_delete.cpp:73:20:
  error: 'operator new' takes type size_t ('unsigned long') as 1st parameter
.../stdlib_new_delete.cpp:97:37:
  error: 'operator new[]' takes type size_t ('unsigned long') as 1st parameter
.../cxa_vector.cpp:173:12:
  error: no matching function for call to '__cxa_vec_new2'

Observed: size_t = unsigned int (from the header). Expected: size_t = unsigned long (to match clang's __SIZE_TYPE__).

Proposed fix

Make wasm32 agree with the compiler, matching every other arch that pins pointer-width types to long:

--- a/arch/wasm32/bits/alltypes.h.in
+++ b/arch/wasm32/bits/alltypes.h.in
@@ -1,1 +1,1 @@
-#define _Addr int
+#define _Addr long

On wasm32 long and int are both 32-bit, so this is ABI-neutral for existing C objects; it only changes the spelling of size_t to the one clang expects, which is what C++ requires. Verified: with this change libc++ + libc++abi (static, no-exceptions, no-RTTI) compile and link cleanly, and an STL test program (std::array / std::sort / std::string_view) builds and runs to a correct result.

Proposed fix targets brintos/musl only — no distro submodule pins moved. All distros share one lineage, so pin bumps are coordinated on merge, not per-engineer.

jdbrinton jdbrinton commented

Fixed on joel-dev: 2bd6c0ac#define _Addr intlong in arch/wasm32/bits/alltypes.h.in, exactly as proposed. Re-verified independently with a RED/GREEN gate against the real generated header (musl's tools/mkalltypes.sed recipe): the type-compatibility probe (size_t/SIZE_TYPE, uintptr_t/UINTPTR_TYPE, ptrdiff_t/PTRDIFF_TYPE, ssize_t/long) fails 4/4 on the unpatched header and compiles clean on the patched one, pinned clang --target=wasm32. _Reg/_Int64 deliberately untouched (register width, not pointer identity); no other pointer-width int found in the arch overlay. Type-identity change only — int/long both 32-bit on wasm32. Lands in images at the next libc pool rebuild + distro build. — agent for joel, 2026-07-14

jdbrinton closed this as completed