Summary
SizeAlign's handling of TypeDefKind::FixedLengthList(ty, size) computes the total size as element_size * length and panics on overflow instead of returning an error:
// crates/wit-parser/src/sizealign.rs:266-273
TypeDefKind::FixedLengthList(t, size) => {
let field_align = self.align(t);
let field_size = self.size(t);
ElementInfo::new(
ArchitectureSize::new(
field_size.bytes.checked_mul(*size as usize).unwrap(), // <-- panics on overflow
field_size.pointers.checked_mul(*size as usize).unwrap(),
),
field_align,
)
}
size is a u32 taken directly from the WIT text list<T, N> syntax (crates/wit-parser/src/ast.rs:1454-1463), parsed with no upper bound — unlike the component binary format, which bounds fixed-length list lengths to MAX_WASM_FIXED_LENGTH_LIST_ELEMENTS = 1 Gi. Nesting two fixed-length lists whose element type has a non-trivial size (e.g. u64) drives element_size * length past usize::MAX, so checked_mul returns None and .unwrap() panics. This fires in release builds too (it's a real panic, not a debug_assert).
SizeAlign::fill(&Resolve) iterates all types in the resolve, so the overflow is reachable even when the oversized fixed-length list is never used by any function signature.
Repro
package test:types;
interface types {
type a = list<u64, 4294967295>;
type b = list<a, 4294967295>;
}
world w { import types; }
Parsing this via wit_parser::Resolve::push_source and computing sizes via SizeAlign::fill (or running wasm-tools wit-dylib on it) panics:
thread 'main' panicked at .../wit-parser-0.257.1/src/sizealign.rs:271:70:
called `Option::unwrap()` on a `None` value
Reproduced on wit-parser 0.230.0 (first version shipping this code, panic at sizealign.rs:268) and 0.257.1 (latest, panic at sizealign.rs:271), and on main HEAD a7ef4778a98ed6d49c7785487dbd95bf053d788d.
Controls confirming it's specifically the multiplication overflow, not a parse error:
| Case |
Result |
type a = list<u64, 2>; type b = list<a, 3> |
exits fine |
type a = list<u64, 4294967295> alone (size 34359738360) |
no overflow, exits fine |
type a = list<u8, 4294967295>; type b = list<a, 4294967295> (size 4294967295² = 18446744065119617025, under u64::MAX) |
no overflow, exits fine |
Two nested list<u64, ...> |
panics |
Happy to open a PR for this if useful.
Summary
SizeAlign's handling ofTypeDefKind::FixedLengthList(ty, size)computes the total size aselement_size * lengthand panics on overflow instead of returning an error:sizeis au32taken directly from the WIT textlist<T, N>syntax (crates/wit-parser/src/ast.rs:1454-1463), parsed with no upper bound — unlike the component binary format, which bounds fixed-length list lengths toMAX_WASM_FIXED_LENGTH_LIST_ELEMENTS = 1 Gi. Nesting two fixed-length lists whose element type has a non-trivial size (e.g.u64) driveselement_size * lengthpastusize::MAX, sochecked_mulreturnsNoneand.unwrap()panics. This fires in release builds too (it's a real panic, not adebug_assert).SizeAlign::fill(&Resolve)iterates all types in the resolve, so the overflow is reachable even when the oversized fixed-length list is never used by any function signature.Repro
Parsing this via
wit_parser::Resolve::push_sourceand computing sizes viaSizeAlign::fill(or runningwasm-tools wit-dylibon it) panics:Reproduced on
wit-parser0.230.0(first version shipping this code, panic atsizealign.rs:268) and0.257.1(latest, panic atsizealign.rs:271), and on main HEADa7ef4778a98ed6d49c7785487dbd95bf053d788d.Controls confirming it's specifically the multiplication overflow, not a parse error:
type a = list<u64, 2>; type b = list<a, 3>type a = list<u64, 4294967295>alone (size 34359738360)type a = list<u8, 4294967295>; type b = list<a, 4294967295>(size 4294967295² = 18446744065119617025, under u64::MAX)list<u64, ...>Happy to open a PR for this if useful.