Issue Description
On 32-bit platforms (e.g., i686-linux-android, armv7-linux-androideabi), the C API header wasmtime/val.h contains static_assert checks that require wasmtime_valunion_t and wasmtime_val_raw_t to be 8-byte aligned:
static_assert(__alignof(wasmtime_valunion_t) == 8, "should be 8-byte aligned");
static_assert(__alignof(wasmtime_val_raw_t) == 8, "should be 8-byte aligned");
However, on 32-bit platforms, int64_t and double only have 4-byte alignment in the C ABI, causing these assertions to fail at compile time.
Additionally, even if the assertions are bypassed, there is a layout mismatch between Rust and C on 32-bit platforms:
|
Rust #[repr(C)] |
C (original val.h) |
| union alignment |
8 (Rust's i64/u64 are always 8-byte aligned) |
4 (C ABI int64_t on 32-bit) |
wasmtime_val_t.of offset |
8 |
4 |
wasmtime_val_t size |
32 |
20 |
This causes the C side to read garbage data for the kind field (e.g., unknown wasmtime_valkind_t: 16), leading to a SIGABRT crash at runtime when calling wasmtime_func_call.
Reproduction
- Build
libwasmtime.a for i686-linux-android (32-bit x86 Android)
- Include
wasmtime/val.h from C++ code compiled with the Android NDK (x86 target)
- Compile fails with
static_assert errors
- If assertions are removed, runtime crash occurs:
Abort message: 'unknown wasmtime_valkind_t: <garbage>'
Crash Log (x86 Android Emulator)
Abort message: 'unknown wasmtime_valkind_t: 16'
signal 6 (SIGABRT), code -1 (SI_QUEUE)
backtrace:
#14 pc ... libwasmline.so (wasmtime_func_call+192)
#15 pc ... libwasmline.so (wasmline::Session::invokeInbound+465)
...
Proposed Fix
Force 8-byte alignment on both C and Rust sides to ensure consistent layout across all platforms:
crates/c-api/include/wasmtime/val.h:
-typedef union wasmtime_valunion {
+typedef union alignas(8) wasmtime_valunion {
-typedef union wasmtime_val_raw {
+typedef union alignas(8) wasmtime_val_raw {
-typedef struct wasmtime_val {
+typedef struct alignas(8) wasmtime_val {
crates/c-api/src/val.rs:
-#[repr(C)]
+#[repr(C, align(8))]
pub struct wasmtime_val_t {
-#[repr(C)]
+#[repr(C, align(8))]
pub union wasmtime_val_union {
And update the compile-time assertion:
const _: () = {
- assert!(std::mem::size_of::<wasmtime_val_union>() <= 24);
- assert!(std::mem::align_of::<wasmtime_val_union>() == std::mem::align_of::<u64>());
+ assert!(std::mem::size_of::<wasmtime_val_union>() <= 32);
+ assert!(std::mem::align_of::<wasmtime_val_union>() == 8);
};
Impact
| Platform |
Before Fix |
After Fix |
| x86_64 / aarch64 (64-bit) |
align=8, works ✅ |
align=8, no change ✅ |
| x86 / armv7a (32-bit) |
align=4, compile fails / runtime crash ❌ |
align=8, works ✅ |
- 64-bit platforms: zero impact (
alignas(8) is redundant, natural alignment is already 8)
- 32-bit platforms: fixes compile-time assertion failure and runtime layout mismatch
- Memory overhead on 32-bit: ~12 bytes per
wasmtime_val_t (negligible for typical usage)
- API compatibility: no changes to type names or function signatures
Environment
- Forked Wasmtime version: 45.0.6 (custom features pulley-min [x86/armv7a] )
- Affected targets:
i686-linux-android, armv7-linux-androideabi (and potentially other 32-bit targets)
- Discovered while building wasmline (a Wasm plugin framework) with Pulley interpreter on 32-bit Android
Fix
Result After Fix

Issue Description
On 32-bit platforms (e.g.,
i686-linux-android,armv7-linux-androideabi), the C API headerwasmtime/val.hcontainsstatic_assertchecks that requirewasmtime_valunion_tandwasmtime_val_raw_tto be 8-byte aligned:However, on 32-bit platforms,
int64_tanddoubleonly have 4-byte alignment in the C ABI, causing these assertions to fail at compile time.Additionally, even if the assertions are bypassed, there is a layout mismatch between Rust and C on 32-bit platforms:
#[repr(C)]val.h)i64/u64are always 8-byte aligned)int64_ton 32-bit)wasmtime_val_t.ofoffsetwasmtime_val_tsizeThis causes the C side to read garbage data for the
kindfield (e.g.,unknown wasmtime_valkind_t: 16), leading to aSIGABRTcrash at runtime when callingwasmtime_func_call.Reproduction
libwasmtime.afori686-linux-android(32-bit x86 Android)wasmtime/val.hfrom C++ code compiled with the Android NDK (x86 target)static_asserterrorsAbort message: 'unknown wasmtime_valkind_t: <garbage>'Crash Log (x86 Android Emulator)
Proposed Fix
Force 8-byte alignment on both C and Rust sides to ensure consistent layout across all platforms:
crates/c-api/include/wasmtime/val.h:crates/c-api/src/val.rs:And update the compile-time assertion:
const _: () = { - assert!(std::mem::size_of::<wasmtime_val_union>() <= 24); - assert!(std::mem::align_of::<wasmtime_val_union>() == std::mem::align_of::<u64>()); + assert!(std::mem::size_of::<wasmtime_val_union>() <= 32); + assert!(std::mem::align_of::<wasmtime_val_union>() == 8); };Impact
alignas(8)is redundant, natural alignment is already 8)wasmtime_val_t(negligible for typical usage)Environment
i686-linux-android,armv7-linux-androideabi(and potentially other 32-bit targets)Fix
Result After Fix