vouillon opened PR #13449 from vouillon:gc-fix to bytecodealliance:main:
SSABuilder::variablesis aSecondaryMap<Variable, SecondaryMap<Block, PackedOption<Value>>>that stores oneValueper(Variable, Block)pair, so eachdef_varoverwrites whatever the prior definition in that block was.values_for_varthen iterates this map and returns only the latestValueper block. That is the wrong set for the safepoint pass:FunctionBuilder::finalizeusesvalues_for_varto propagate stack-map flags from a variable onto its associated values, and any earlier SSA value bound to the variable in the same block is silently dropped even if it is still live across a later safepoint.Concretely, Wasm code that re-defines a stack-map variable while an earlier SSA value bound to it is still live on the operand stack across an intervening safepoint hits the pattern:
local.get N ;; pushes the SSA value of the first def ... call $foo ;; safepoint local.tee N ;; redefines the variable ... array.new_fixed ;; another safepoint that may GCWithout this fix the safepoint pass omits the first def's value from the stack map, GC's trace doesn't mark it, sweep removes it from OASR, the slot is freed, and the subsequent init-barrier in
array.new_fixedinc-refs a freed slot, corrupting the OASR list.Add
all_var_values: SecondaryMap<Variable, EntitySet<Value>>toSSABuilder, and maintain the invariant that everyValuewritten tovariables[var][block]is also inall_var_values[var]. The only places that store aValueintovariables[var][block]for the first time aredef_varandfind_var's block-param-creation tail, so those are the two sites that need to insert.use_var_nonlocal's predecessor-copy loop only re-stores avalthatfind_varjust
returned, so the value is already inall_var_values; adebug_assert!documents and checks this. Finally switch
values_for_varto iterate the new set.
vouillon requested wasmtime-compiler-reviewers for a review on PR #13449.
vouillon requested cfallin for a review on PR #13449.
github-actions[bot] added the label cranelift on PR #13449.
:thumbs_up: cfallin submitted PR review:
Good find -- thank you!
cfallin added PR #13449 cranelift: include every SSA value bound to a variable in stack maps to the merge queue.
:check: cfallin merged PR #13449.
cfallin removed PR #13449 cranelift: include every SSA value bound to a variable in stack maps from the merge queue.
:memo: bjorn3 submitted PR review.
:speech_balloon: bjorn3 created PR review comment:
I don't think this should use
EntitySet.EntitySetusesO(max value id)memory rather thanO(number of values on the set)memory, which will waste a lot of memory for these sparse sets.Also would it be possible to skip maintaining this info when stack maps are not requested by the user of Cranelift?
Last updated: Jun 01 2026 at 09:49 UTC