Wasm translation bugfix: properly clean up value stack for else-branch when if-branch ends in unreachable.

The Wasm translation handles unreachable code sections
specially, skipping ops until the end of a block and a control-flow
merger at which code becomes reachable again. Unfortunately, while the
ordinary else-op handler properly sets up the value stack for the
else-branch with the parameters to the if/else, the unreachable-case
else-op handler did not. This resulted in a bad translation and CLIF
type error despite valid Wasm.

Found via fuzzing by :decoder in
https://bugzilla.mozilla.org/show_bug.cgi?id=1657895.
This commit is contained in:
Chris Fallin
2020-08-07 18:33:04 -07:00
parent a796d65467
commit dd5a5ebdbc
2 changed files with 50 additions and 1 deletions

View File

@@ -1888,13 +1888,21 @@ fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>(
let (params, _results) = let (params, _results) =
blocktype_params_results(module_translation_state, blocktype)?; blocktype_params_results(module_translation_state, blocktype)?;
let else_block = block_with_params(builder, params, environ)?; let else_block = block_with_params(builder, params, environ)?;
state.stack.truncate(
state.control_stack.last().unwrap().original_stack_size(),
);
// We change the target of the branch instruction. // We change the target of the branch instruction.
builder.change_jump_destination(branch_inst, else_block); builder.change_jump_destination(branch_inst, else_block);
builder.seal_block(else_block); builder.seal_block(else_block);
else_block else_block
} }
ElseData::WithElse { else_block } => else_block, ElseData::WithElse { else_block } => {
state.stack.truncate(
state.control_stack.last().unwrap().original_stack_size(),
);
else_block
}
}; };
builder.switch_to_block(else_block); builder.switch_to_block(else_block);

View File

@@ -0,0 +1,41 @@
(module
(type (;0;) (func (param i32)))
(func $main (type 0) (param i32)
i32.const 35
loop (param i32) ;; label = @1
local.get 0
if (param i32) ;; label = @2
i64.load16_s align=1
unreachable
unreachable
unreachable
unreachable
unreachable
local.get 0
unreachable
unreachable
i64.load8_u offset=11789
unreachable
else
i32.popcnt
local.set 0
return
unreachable
end
unreachable
unreachable
nop
f32.lt
i32.store8 offset=82
unreachable
end
unreachable
unreachable
unreachable
unreachable)
(table (;0;) 63 255 funcref)
(memory (;0;) 13 16)
(export "t1" (table 0))
(export "m1" (memory 0))
(export "main" (func $main))
(export "memory" (memory 0)))