Fix Wasm translator to handle loop parameters on br_table default target.
Similar to an earlier issue for ordinary branches (fixed in PR #1833), the cranelift-wasm crate did not previously correctly translate a br_table instruction's default-target branch when the branch target was a loop with loop parameters. The mistranslated CLIF resulted in a validation error. This one-line fix simply fills in the correct parameter count, generating a jump instruction with the appropriate parameters from the stack. This issue was found by :decoder in the SpiderMonkey embedding of Cranelift, in https://bugzilla.mozilla.org/show_bug.cgi?id=1657062. The test case is from that bug report.
This commit is contained in:
@@ -395,7 +395,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
let i = state.control_stack.len() - 1 - (min_depth as usize);
|
||||
let min_depth_frame = &state.control_stack[i];
|
||||
if min_depth_frame.is_loop() {
|
||||
0
|
||||
min_depth_frame.num_param_values()
|
||||
} else {
|
||||
min_depth_frame.num_return_values()
|
||||
}
|
||||
|
||||
640
tests/misc_testsuite/br-table-fuzzbug.wast
Normal file
640
tests/misc_testsuite/br-table-fuzzbug.wast
Normal file
@@ -0,0 +1,640 @@
|
||||
;; From https://bugzilla.mozilla.org/show_bug.cgi?id=1657062.
|
||||
;;
|
||||
;; This just tests that Cranelift can compile this function; it previously
|
||||
;; triggered a validator error on the CLIF that is generated by the wasm crate.
|
||||
|
||||
(module
|
||||
(type (;0;) (func (param i32 i32 i32) (result i32)))
|
||||
(func $main (type 0) (param i32 i32 i32) (result i32)
|
||||
local.get 1
|
||||
i32.const 6150
|
||||
local.get 2
|
||||
i32.const -63
|
||||
br_if 0 (;@0;)
|
||||
loop (param i32 i32 i32) (result i32) ;; label = @1
|
||||
i32.const -59
|
||||
local.get 1
|
||||
i32.const -49
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
i32.const 0
|
||||
i32.const 0
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.const 27
|
||||
select
|
||||
i32.const 24
|
||||
select
|
||||
local.get 0
|
||||
i32.const 27
|
||||
i32.const 32
|
||||
br_if 0 (;@1;)
|
||||
i32.const 32
|
||||
br_if 0 (;@1;)
|
||||
i32.const 452672
|
||||
i32.const 32
|
||||
br_if 1 (;@0;)
|
||||
i32.const -23
|
||||
i32.div_s
|
||||
local.get 1
|
||||
if ;; label = @2
|
||||
nop
|
||||
i32.const -52
|
||||
if ;; label = @3
|
||||
nop
|
||||
i32.const -52
|
||||
local.tee 1
|
||||
br_table 1 (;@2;) 0 (;@3;)
|
||||
end
|
||||
local.get 2
|
||||
br_table 0 (;@2;) 0 (;@2;)
|
||||
end
|
||||
local.get 1
|
||||
nop
|
||||
i32.const -23
|
||||
i32.div_s
|
||||
nop
|
||||
i32.const -25
|
||||
i32.popcnt
|
||||
select
|
||||
select
|
||||
i32.const 139
|
||||
select
|
||||
drop
|
||||
i32.const -8051
|
||||
nop
|
||||
drop
|
||||
i32.const 27
|
||||
i32.const -63
|
||||
local.get 1
|
||||
i32.const 1
|
||||
i32.const -63
|
||||
i32.const 2
|
||||
i32.const -6145
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
select
|
||||
local.get 1
|
||||
i32.const -7937
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
i32.eqz
|
||||
i32.const -49
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 32
|
||||
call $main
|
||||
i32.const -1
|
||||
i32.rem_s
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const -49
|
||||
i32.const 0
|
||||
i32.const 0
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
local.get 1
|
||||
select
|
||||
i32.const 32
|
||||
call $main
|
||||
i32.const -1
|
||||
i32.rem_s
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 3
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const -64
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
select
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
local.get 1
|
||||
select
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const -64
|
||||
i32.ge_u
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
nop
|
||||
i32.const -59
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.const 32
|
||||
select
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
local.get 1
|
||||
select
|
||||
i32.const 32
|
||||
br_if 0 (;@1;)
|
||||
i32.const 4
|
||||
i32.rem_s
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.const -19
|
||||
nop
|
||||
nop
|
||||
i32.const -23
|
||||
i32.div_s
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const -63
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.div_s
|
||||
local.get 1
|
||||
i32.const 1
|
||||
i32.const -63
|
||||
i32.const 2
|
||||
i32.const 1
|
||||
drop
|
||||
i32.const -63
|
||||
i32.const 27
|
||||
select
|
||||
i32.const 27
|
||||
select
|
||||
local.tee 0
|
||||
i32.const 27
|
||||
i32.const 32
|
||||
br_if 0 (;@1;)
|
||||
i32.const 32
|
||||
br_if 0 (;@1;)
|
||||
i32.const 452672
|
||||
i32.const 32
|
||||
br_if 1 (;@0;)
|
||||
i32.const -23
|
||||
i32.div_s
|
||||
local.get 1
|
||||
if ;; label = @2
|
||||
nop
|
||||
i32.const -52
|
||||
if ;; label = @3
|
||||
nop
|
||||
i32.const -52
|
||||
local.tee 1
|
||||
br_table 1 (;@2;) 0 (;@3;)
|
||||
end
|
||||
local.get 2
|
||||
br_table 0 (;@2;) 0 (;@2;)
|
||||
end
|
||||
local.get 1
|
||||
nop
|
||||
i32.const -23
|
||||
i32.div_s
|
||||
nop
|
||||
i32.const -25
|
||||
i32.popcnt
|
||||
select
|
||||
select
|
||||
i32.const 139
|
||||
select
|
||||
drop
|
||||
i32.const -64
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
select
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
local.get 1
|
||||
select
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const -64
|
||||
i32.ge_u
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
nop
|
||||
i32.const -59
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.const 32
|
||||
select
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
local.get 1
|
||||
select
|
||||
i32.const 32
|
||||
br_if 0 (;@1;)
|
||||
i32.const 4
|
||||
i32.rem_s
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.const -19
|
||||
nop
|
||||
nop
|
||||
i32.const -23
|
||||
i32.div_s
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const -63
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.div_s
|
||||
local.get 1
|
||||
i32.const 1
|
||||
i32.const -63
|
||||
i32.const 2
|
||||
i32.const 1
|
||||
drop
|
||||
nop
|
||||
i32.const -49
|
||||
br_if 0 (;@1;)
|
||||
local.set 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
i32.const 0
|
||||
i32.const 0
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
local.get 1
|
||||
select
|
||||
i32.const 32
|
||||
call $main
|
||||
i32.const -1
|
||||
i32.rem_s
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const -64
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
select
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
local.get 1
|
||||
select
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const -64
|
||||
i32.ge_u
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
nop
|
||||
i32.const -59
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.const 32
|
||||
select
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
local.get 1
|
||||
select
|
||||
i32.const 32
|
||||
br_if 0 (;@1;)
|
||||
i32.const 4
|
||||
i32.rem_s
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const -63
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.div_s
|
||||
local.get 1
|
||||
i32.const 1
|
||||
i32.const -63
|
||||
i32.const 2
|
||||
i32.const 1
|
||||
drop
|
||||
i32.const -63
|
||||
i32.const 27
|
||||
select
|
||||
i32.const 27
|
||||
select
|
||||
local.tee 0
|
||||
i32.const 27
|
||||
i32.const 32
|
||||
br_if 0 (;@1;)
|
||||
i32.const 32
|
||||
br_if 0 (;@1;)
|
||||
i32.const 452672
|
||||
i32.const 32
|
||||
br_if 1 (;@0;)
|
||||
i32.const -23
|
||||
i32.div_s
|
||||
local.get 1
|
||||
if ;; label = @2
|
||||
nop
|
||||
i32.const -52
|
||||
if ;; label = @3
|
||||
nop
|
||||
i32.const -52
|
||||
local.tee 1
|
||||
br_table 1 (;@2;) 0 (;@3;)
|
||||
end
|
||||
local.get 2
|
||||
br_table 0 (;@2;) 0 (;@2;)
|
||||
end
|
||||
local.get 1
|
||||
nop
|
||||
i32.const -23
|
||||
i32.div_s
|
||||
nop
|
||||
i32.const -25
|
||||
i32.popcnt
|
||||
select
|
||||
select
|
||||
i32.const 139
|
||||
select
|
||||
drop
|
||||
i32.const -64
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
select
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
local.get 1
|
||||
select
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const -64
|
||||
i32.ge_u
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
nop
|
||||
i32.const -59
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.const 32
|
||||
select
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
local.get 1
|
||||
select
|
||||
i32.const 32
|
||||
br_if 0 (;@1;)
|
||||
i32.const 4
|
||||
i32.rem_s
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
br_table 0 (;@1;)
|
||||
unreachable
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.const -19
|
||||
nop
|
||||
nop
|
||||
i32.const -23
|
||||
i32.div_s
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const -63
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.div_s
|
||||
local.get 1
|
||||
i32.const 1
|
||||
i32.const -63
|
||||
i32.const 2
|
||||
i32.const 1
|
||||
drop
|
||||
nop
|
||||
i32.const -49
|
||||
br_if 0 (;@1;)
|
||||
local.set 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
i32.const 0
|
||||
i32.const 0
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
local.get 1
|
||||
select
|
||||
i32.const 32
|
||||
call $main
|
||||
i32.const -1
|
||||
i32.rem_s
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const -64
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
select
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
local.get 1
|
||||
select
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const -64
|
||||
i32.ge_u
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
i32.ge_u
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.ge_u
|
||||
nop
|
||||
i32.const -59
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
i32.const 32
|
||||
select
|
||||
br_if 0 (;@1;)
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const 0
|
||||
i32.const 2
|
||||
i32.const -63
|
||||
i32.const 27
|
||||
i32.const -63
|
||||
i32.eqz
|
||||
i32.eqz
|
||||
br 0 (;@1;)
|
||||
end
|
||||
unreachable
|
||||
i32.div_s
|
||||
unreachable
|
||||
i32.rem_s
|
||||
i32.div_s
|
||||
return
|
||||
br_if 0 (;@0;)
|
||||
i32.const 0
|
||||
i32.extend8_s
|
||||
unreachable
|
||||
unreachable
|
||||
unreachable
|
||||
unreachable
|
||||
i32.ctz
|
||||
unreachable
|
||||
i32.ge_u
|
||||
unreachable
|
||||
unreachable
|
||||
i32.popcnt
|
||||
unreachable
|
||||
unreachable
|
||||
i32.popcnt)
|
||||
(export "main" (func $main)))
|
||||
Reference in New Issue
Block a user