Skip to content

Fix passive element segment GC roots' endianness#13230

Merged
fitzgen merged 3 commits intobytecodealliance:mainfrom
fitzgen:passive-element-segment-gc-roots-endianness
Apr 29, 2026
Merged

Fix passive element segment GC roots' endianness#13230
fitzgen merged 3 commits intobytecodealliance:mainfrom
fitzgen:passive-element-segment-gc-roots-endianness

Conversation

@fitzgen
Copy link
Copy Markdown
Member

@fitzgen fitzgen commented Apr 29, 2026

Passive element segments were registered as GC roots by converting a *mut ValRaw to a *mut VMGcRef. Because we always store GC refs as little endian inside ValRaw, regardless of the target architecture's endianness, this cast is only valid on little endian systems. This bug was not exposed until the introduction of the copying collector in
#13107

The fix that this commit makes is to add another kind of GC root for ValRaw, where we can get and set the GC root using ValRaw internally, to ensure that the endianness (and incidentally also the GC ref offsets within the ValRaw) are matched up correctly between the GC root's definition and the collector's use of it. This brings us to three kinds of GC roots: Wasm stack roots, VMGcRef roots, and ValRaw roots.

FWIW, I initially tried to make VMGcRef also always store its data as little endian, but this was a larger, more-invasive change and with feedback like #13193 (comment) suggesting the use of [u8; 4] instead of u32 to make the byte ordering explicit, we break rustc's niche type optimizations (since VMGcRef is non-zero right now). I also investigated making PassiveElementSegment an enum or either funcrefs or GC refs, similar to what we do for wasmtime::runtime::vm::Table. This also led to an outsized amount of code churn and didn't feel like it was paying for itself. Ultimately, I abandoned these approaches, preferring the one taken in this commit instead.

@fitzgen fitzgen requested a review from a team as a code owner April 29, 2026 13:27
@fitzgen fitzgen requested review from pchickey and removed request for a team April 29, 2026 13:27
Passive element segments were registered as GC roots by converting a `*mut
ValRaw` to a `*mut VMGcRef`. Because we always store GC refs as little endian
inside `ValRaw`, regardless of the target architecture's endianness, this cast
is only valid on little endian systems. This bug was not exposed until the
introduction of the copying collector in
bytecodealliance#13107

The fix that this commit makes is to add another kind of GC root for `ValRaw`,
where we can get and set the GC root using `ValRaw` internally, to ensure that
the endianness (and incidentally also the GC ref offsets within the `ValRaw`)
are matched up correctly between the GC root's definition and the collector's
use of it. This brings us to three kinds of GC roots: Wasm stack roots,
`VMGcRef` roots, and `ValRaw` roots.

FWIW, I initially tried to make `VMGcRef` also always store its data as little
endian, but this was a larger, more-invasive change and with feedback like
bytecodealliance#13193 (comment)
suggesting the use of `[u8; 4]` instead of `u32` to make the byte ordering
explicit, we break `rustc`'s niche type optimizations (since `VMGcRef` is
non-zero right now). I also investigated making `PassiveElementSegment` an
`enum` or either funcrefs or externrefs, similar to what we do for
`wasmtime::runtime::vm::Table`. This also led to an outsized amount of code
churn and didn't feel like it was paying for itself. Ultimately, I abandoned
these approaches, preferring the one taken in this commit instead.
@fitzgen fitzgen force-pushed the passive-element-segment-gc-roots-endianness branch from 01300c0 to 705f1b8 Compare April 29, 2026 13:29
Copy link
Copy Markdown
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find!

Comment thread crates/wasmtime/src/runtime/vm/gc/gc_runtime.rs Outdated
@fitzgen fitzgen enabled auto-merge April 29, 2026 13:45
@fitzgen fitzgen added this pull request to the merge queue Apr 29, 2026
Merged via the queue into bytecodealliance:main with commit ad9bc5b Apr 29, 2026
48 checks passed
@fitzgen fitzgen deleted the passive-element-segment-gc-roots-endianness branch April 29, 2026 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants