brintos

brintos / musl public Read only

0
0

wasm32: size_t is unsigned int but clang __SIZE_TYPE__ is unsigned long — breaks C++ operator new #2

Closed sasha opened this issue · 1 comment
S sasha commented

Summary

On wasm32-hwjs the C library and the compiler disagree on the underlying type of size_t, which makes it impossible to build any C++ / libc++ for the target.

  • Compiler (fork clang, wasm32-hwjs-linux-musl): __SIZE_TYPE__ = long unsigned int (unsigned long).
  • musl (arch/wasm32/bits/alltypes.h.in): #define _Addr inttypedef unsigned _Addr size_t; = unsigned int.

Both are 4 bytes on wasm32, but they are distinct types. Clang special-cases the replaceable global operator new to require its parameter be exactly __SIZE_TYPE__, so libcxxabi's operator new (declared with musl's size_t) is rejected:

error: 'operator new' takes type size_t ('unsigned long') as 1st parameter
error: no overload of 'operator new[]' matching 'void *(*)(size_t)' (aka 'void *(*)(unsigned int)')

This is inert in C (the entire C userland — busybox, bash, coreutils — builds fine), so it stayed latent until the first C++ build on the target (bringing up libc++ for an on-target clang).

Reproduction

$ echo | wasmcc -dM -E -x c++ - | grep __SIZE_TYPE__
#define __SIZE_TYPE__ long unsigned int

$ printf '#include <stddef.h>\n_Static_assert(__builtin_types_compatible_p(size_t, unsigned long),"");\n' \
    | wasmcc -c -x c -o /dev/null -
error: static assertion failed ... (size_t is 'unsigned int', not 'unsigned long')

Building LLVM_ENABLE_RUNTIMES=libcxx;libcxxabi;libunwind for wasm32-hwjs fails on libcxxabi/src/stdlib_new_delete.cpp and cxa_vector.cpp with the errors above.

Proposed fix

Set _Addr = long in arch/wasm32/bits/alltypes.h.in so size_t (and the other _Addr-based types: ptrdiff_t, ssize_t, intptr_t, …) is unsigned long, matching the compiler's __SIZE_TYPE__ and the wasm32 ABI convention (upstream LLVM / wasi-libc use unsigned long for size_t on wasm32). Byte-compatible on wasm32 (int == long == 32-bit) — only the type identity changes, so the C ABI and the prebuilt C userland are unaffected.

Confirmed end-to-end: regenerating bits/alltypes.h from the patched .in via musl's own mkalltypes.sed yields size_t = unsigned long, and with that header libc++ / libc++abi / libunwind build cleanly for wasm32-hwjs (previously blocked at operator new).

Branch: fix/wasm32-size_t-addr-long Commit: 1a12e2b

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

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

Duplicate of #1 (same root cause: _Addr int in arch/wasm32/bits/alltypes.h.in vs clang's __SIZE_TYPE__ = unsigned long). Fixed on joel-dev in 2bd6c0ac — the libc side was changed to match the compiler (matching x86_64/aarch64/riscv64's _Addr long idiom), rather than changing clang, so existing wasm32 codegen and the compiler's builtin type expectations stay canonical. See #1 for the RED/GREEN verification. — agent for joel, 2026-07-14

jdbrinton closed this as completed