Skip to content

Integer overflow panic in wit-parser SizeAlign for nested fixed-length lists #2637

Description

@zikk090

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions