From d4d3f2c599a2dfab3ba900fd2be122a4053f9fd7 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Mon, 19 Sep 2016 04:56:19 +0200 Subject: [PATCH 1/5] Type-check dead code and introduce assert_soft_invalid --- ml-proto/README.md | 4 + ml-proto/host/arrange.ml | 2 + ml-proto/host/flags.ml | 1 + ml-proto/host/js.ml | 10 ++ ml-proto/host/lexer.mll | 1 + ml-proto/host/main.ml | 1 + ml-proto/host/parser.mly | 4 +- ml-proto/host/run.ml | 12 +- ml-proto/host/script.ml | 1 + ml-proto/spec/check.ml | 167 ++++++++++++------------ ml-proto/spec/types.ml | 7 +- ml-proto/test/block.wast | 33 ----- ml-proto/test/br.wast | 21 ++- ml-proto/test/br_if.wast | 15 --- ml-proto/test/br_table.wast | 24 ++-- ml-proto/test/func.wast | 9 -- ml-proto/test/loop.wast | 15 --- ml-proto/test/return.wast | 10 +- ml-proto/test/soft-fail.wast | 226 +++++++++++++++++++++++++++++++++ ml-proto/test/unreachable.wast | 6 +- 20 files changed, 374 insertions(+), 195 deletions(-) create mode 100644 ml-proto/test/soft-fail.wast diff --git a/ml-proto/README.md b/ml-proto/README.md index cb3cb440b8..04df6462fb 100644 --- a/ml-proto/README.md +++ b/ml-proto/README.md @@ -96,6 +96,7 @@ wasm -d script.wast -o script.js The first creates a new test scripts where all embedded modules are converted to binary, the second one where all are converted to textual. The last invocation produces an equivalent, self-contained JavaScript test file. +By default, the generated script will require `assert_soft_invalid` (see below) to detect validation failures. Use the `-us` flag ("unchecked soft") to deactivate these assertions to run on implementations that do not validate dead code. #### Command Line Expressions @@ -274,6 +275,7 @@ assertion: ( assert_trap ) ;; assert action traps with given failure string ( assert_malformed ) ;; assert module cannot be decoded with given failure string ( assert_invalid ) ;; assert module is invalid with given failure string + ( assert_soft_invalid ) ;; assert module is for cases that are not required to be checked ( assert_unlinkable ) ;; assert module fails to link meta: @@ -293,6 +295,8 @@ The `input` and `output` meta commands determine the requested file format from The interpreter supports a "dry" mode (flag `-d`), in which modules are only validated. In this mode, all actions and assertions are ignored. It also supports an "unchecked" mode (flag `-u`), in which module definitions are not validated before use. +Finally, "unchecked soft" mode (flag `-us`), will not require `assert_soft_valid` assertions to succeed. When outputing JavaScript scripts, this flag also controls how the created script implements this assertions. + ## Abstract Syntax The abstract WebAssembly syntax, as described above and in the [design doc](https://github.com/WebAssembly/design/blob/master/AstSemantics.md), is defined in [ast.ml](https://github.com/WebAssembly/spec/blob/master/ml-proto/spec/ast.ml). diff --git a/ml-proto/host/arrange.ml b/ml-proto/host/arrange.ml index 311f6cc559..c88c4c90ae 100644 --- a/ml-proto/host/arrange.ml +++ b/ml-proto/host/arrange.ml @@ -408,6 +408,8 @@ let assertion mode ass = Node ("assert_malformed", [definition `Original None def; Atom (string re)]) | AssertInvalid (def, re) -> Node ("assert_invalid", [definition mode None def; Atom (string re)]) + | AssertSoftInvalid (def, re) -> + Node ("assert_soft_invalid", [definition mode None def; Atom (string re)]) | AssertUnlinkable (def, re) -> Node ("assert_unlinkable", [definition mode None def; Atom (string re)]) | AssertReturn (act, lits) -> diff --git a/ml-proto/host/flags.ml b/ml-proto/host/flags.ml index 2554fba0f9..00b8e6fde3 100644 --- a/ml-proto/host/flags.ml +++ b/ml-proto/host/flags.ml @@ -1,6 +1,7 @@ let interactive = ref false let trace = ref false let unchecked = ref false +let unchecked_soft = ref false let print_sig = ref false let dry = ref false let width = ref 80 diff --git a/ml-proto/host/js.ml b/ml-proto/host/js.ml index ea93225fed..0656fff8a9 100644 --- a/ml-proto/host/js.ml +++ b/ml-proto/host/js.ml @@ -9,6 +9,8 @@ open Source let prefix = "'use strict';\n" ^ "\n" ^ + "let soft_validate = " ^ string_of_bool (not !Flags.unchecked_soft) ^ ";\n" ^ + "\n" ^ "let spectest = {\n" ^ " print: print || ((...xs) => console.log(...xs)),\n" ^ " global: 666,\n" ^ @@ -44,6 +46,12 @@ let prefix = " throw new Error(\"Wasm validation failure expected\");\n" ^ "}\n" ^ "\n" ^ + "function assert_soft_invalid(bytes) {\n" ^ + " try { module(bytes) } catch (e) { return }\n" ^ + " if (soft_validate)\n" ^ + " throw new Error(\"Wasm validation failure expected\");\n" ^ + "}\n" ^ + "\n" ^ "function assert_unlinkable(bytes) {\n" ^ " let mod = module(bytes);\n" ^ " try { new WebAssembly.Instance(mod, registry) } catch (e) { return }\n" ^ @@ -253,6 +261,8 @@ let of_assertion mods ass = "assert_malformed(" ^ of_definition def ^ ");" | AssertInvalid (def, _) -> "assert_invalid(" ^ of_definition def ^ ");" + | AssertSoftInvalid (def, _) -> + "assert_soft_invalid(" ^ of_definition def ^ ");" | AssertUnlinkable (def, _) -> "assert_unlinkable(" ^ of_definition def ^ ");" | AssertReturn (act, lits) -> diff --git a/ml-proto/host/lexer.mll b/ml-proto/host/lexer.mll index 1e71ba7010..e0e06a5341 100644 --- a/ml-proto/host/lexer.mll +++ b/ml-proto/host/lexer.mll @@ -306,6 +306,7 @@ rule token = parse | "get" { GET } | "assert_malformed" { ASSERT_MALFORMED } | "assert_invalid" { ASSERT_INVALID } + | "assert_soft_invalid" { ASSERT_SOFT_INVALID } | "assert_unlinkable" { ASSERT_UNLINKABLE } | "assert_return" { ASSERT_RETURN } | "assert_return_nan" { ASSERT_RETURN_NAN } diff --git a/ml-proto/host/main.ml b/ml-proto/host/main.ml index f34e601589..38f0c35c06 100644 --- a/ml-proto/host/main.ml +++ b/ml-proto/host/main.ml @@ -26,6 +26,7 @@ let argspec = Arg.align " configure output width (default is 80)"; "-s", Arg.Set Flags.print_sig, " show module signatures"; "-u", Arg.Set Flags.unchecked, " unchecked, do not perform validation"; + "-us", Arg.Set Flags.unchecked_soft, " do not perform soft validation checks"; "-d", Arg.Set Flags.dry, " dry, do not run program"; "-t", Arg.Set Flags.trace, " trace execution"; "-v", Arg.Unit banner, " show version" diff --git a/ml-proto/host/parser.mly b/ml-proto/host/parser.mly index 8123216372..78843c27e8 100644 --- a/ml-proto/host/parser.mly +++ b/ml-proto/host/parser.mly @@ -164,7 +164,7 @@ let inline_type c t at = %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL %token MODULE TABLE ELEM MEMORY DATA OFFSET IMPORT EXPORT TABLE %token SCRIPT REGISTER INVOKE GET -%token ASSERT_MALFORMED ASSERT_INVALID ASSERT_UNLINKABLE +%token ASSERT_MALFORMED ASSERT_INVALID ASSERT_SOFT_INVALID ASSERT_UNLINKABLE %token ASSERT_RETURN ASSERT_RETURN_NAN ASSERT_TRAP %token INPUT OUTPUT %token EOF @@ -686,6 +686,8 @@ assertion : { AssertMalformed (snd $3, $4) @@ at () } | LPAR ASSERT_INVALID module_ TEXT RPAR { AssertInvalid (snd $3, $4) @@ at () } + | LPAR ASSERT_SOFT_INVALID module_ TEXT RPAR + { AssertSoftInvalid (snd $3, $4) @@ at () } | LPAR ASSERT_UNLINKABLE module_ TEXT RPAR { AssertUnlinkable (snd $3, $4) @@ at () } | LPAR ASSERT_RETURN action const_list RPAR { AssertReturn ($3, $4) @@ at () } diff --git a/ml-proto/host/run.ml b/ml-proto/host/run.ml index df9e919e1d..e4175f0bfe 100644 --- a/ml-proto/host/run.ml +++ b/ml-proto/host/run.ml @@ -271,8 +271,14 @@ let run_assertion ass = Assert.error ass.at "expected decoding error" ) - | AssertInvalid (def, re) -> - trace "Asserting invalid..."; + | AssertInvalid (def, re) + | AssertSoftInvalid (def, re) -> + let active = + match ass.it with + | AssertSoftInvalid _ -> not !Flags.unchecked_soft + | _ -> true + in + trace ("Asserting " ^ (if active then "" else "soft ") ^ "invalid..."); (match let m = run_definition def in Check.check_module m @@ -284,7 +290,7 @@ let run_assertion ass = Assert.error ass.at "wrong validation error" end | _ -> - Assert.error ass.at "expected validation error" + if active then Assert.error ass.at "expected validation error" ) | AssertUnlinkable (def, re) -> diff --git a/ml-proto/host/script.ml b/ml-proto/host/script.ml index 8dbae17957..a46e15d5ed 100644 --- a/ml-proto/host/script.ml +++ b/ml-proto/host/script.ml @@ -14,6 +14,7 @@ type assertion = assertion' Source.phrase and assertion' = | AssertMalformed of definition * string | AssertInvalid of definition * string + | AssertSoftInvalid of definition * string | AssertUnlinkable of definition * string | AssertReturn of action * Ast.literal list | AssertReturnNaN of action diff --git a/ml-proto/spec/check.ml b/ml-proto/spec/check.ml index 1af804ae33..fe26850fd2 100644 --- a/ml-proto/spec/check.ml +++ b/ml-proto/spec/check.ml @@ -11,16 +11,9 @@ exception Invalid = Invalid.Error let error = Invalid.error let require b at s = if not b then error at s -let result_error at r1 r2 = - error at - ("type mismatch: operator requires " ^ string_of_result_type r1 ^ - " but stack has " ^ string_of_result_type r2) - (* Context *) -type op_type = stack_type * result_type - type context = { module_ : module_; @@ -52,12 +45,44 @@ let table c x = lookup "table" c.tables x let memory c x = lookup "memory" c.memories x -(* Join *) +(* Stack typing *) + +type ellipses = NoEllipses | Ellipses +type infer_stack_type = ellipses * value_type option list +type op_type = {ins : infer_stack_type; outs : infer_stack_type} + +let known = List.map (fun t -> Some t) +let stack ts = (NoEllipses, known ts) +let (-~>) ts1 ts2 = {ins = NoEllipses, ts1; outs = NoEllipses, ts2} +let (-->) ts1 ts2 = {ins = NoEllipses, known ts1; outs = NoEllipses, known ts2} +let (-->...) ts1 ts2 = {ins = Ellipses, known ts1; outs = Ellipses, known ts2} + +let string_of_infer_type t = + Lib.Option.get (Lib.Option.map string_of_value_type t) "_" +let string_of_infer_types ts = + "[" ^ String.concat " " (List.map string_of_infer_type ts) ^ "]" + +let eq_ty t1 t2 = (t1 = t2 || t1 = None || t2 = None) +let check_stack ts1 ts2 at = + require (List.length ts1 = List.length ts2 && List.for_all2 eq_ty ts1 ts2) at + ("type mismatch: operator requires " ^ string_of_infer_types ts1 ^ + " but stack has " ^ string_of_infer_types ts2) + +let pop (ell1, ts1) (ell2, ts2) at = + let n1 = List.length ts1 in + let n2 = List.length ts2 in + let n = min n1 n2 in + let n3 = if ell2 = Ellipses then (n1 - n) else 0 in + check_stack ts1 (Lib.List.make n3 None @ Lib.List.drop (n2 - n) ts2) at; + (ell2, if ell1 = Ellipses then [] else Lib.List.take (n2 - n) ts2) -let check_join ts r at = - match r with - | Bot -> () - | Stack ts' -> if ts <> ts' then result_error at (Stack ts) r +let push (ell1, ts1) (ell2, ts2) = + assert (ell1 = NoEllipses || ts2 = []); + (if ell1 = Ellipses || ell2 = Ellipses then Ellipses else NoEllipses), + ts2 @ ts1 + +let peek i (ell, ts) = + try List.nth ts i with Failure _ -> None (* Type Synthesis *) @@ -122,14 +147,7 @@ let check_memop (c : context) (memop : 'a memop) get_sz at = let check_arity n at = require (n <= 1) at "invalid result arity, larger than 1 is not (yet) allowed" -let check_result_arity r at = - match r with - | Stack ts -> check_arity (List.length ts) at - | Bot -> () - (* - * check_instr : context -> instr -> stack_type -> unit - * * Conventions: * c : context * e : instr @@ -137,154 +155,141 @@ let check_result_arity r at = * v : value * t : value_type var * ts : stack_type + * + * Note: To deal with the non-determinism in some of the declarative rules, + * the function takes the current stack `s` as an additional argument, allowing + * it to "peek" when it would otherwise have to guess an input type. *) -let (-->) ts r = ts, r - -let peek i ts = - try List.nth ts i with Failure _ -> I32Type - -let peek_n n ts = - let m = min n (List.length ts) in - Lib.List.take m ts @ Lib.List.make (n - m) I32Type - -let rec check_instr (c : context) (e : instr) (stack : stack_type) : op_type = +let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = match e.it with | Unreachable -> - [] --> Bot + [] -->... [] | Nop -> - [] --> Stack [] + [] --> [] | Drop -> - [peek 0 stack] --> Stack [] + [peek 0 s] -~> [] | Block (ts, es) -> check_arity (List.length ts) e.at; - let c' = {c with labels = ts :: c.labels} in - check_block c' es ts e.at; - [] --> Stack ts + check_block {c with labels = ts :: c.labels} es ts e.at; + [] --> ts | Loop (ts, es) -> check_arity (List.length ts) e.at; - let c' = {c with labels = [] :: c.labels} in - check_block c' es ts e.at; - [] --> Stack ts + check_block {c with labels = [] :: c.labels} es ts e.at; + [] --> ts | Br x -> - label c x --> Bot + label c x -->... [] | BrIf x -> - (label c x @ [I32Type]) --> Stack (label c x) + (label c x @ [I32Type]) --> label c x | BrTable (xs, x) -> let ts = label c x in - List.iter (fun x' -> check_join ts (Stack (label c x')) x'.at) xs; - (ts @ [I32Type]) --> Bot + List.iter (fun x' -> check_stack (known ts) (known (label c x')) x'.at) xs; + (label c x @ [I32Type]) -->... [] | Return -> - c.results --> Bot + c.results -->... [] | If (ts, es1, es2) -> check_arity (List.length ts) e.at; - let c' = {c with labels = ts :: c.labels} in - check_block c' es1 ts e.at; - check_block c' es2 ts e.at; - [I32Type] --> Stack ts + check_block {c with labels = ts :: c.labels} es1 ts e.at; + check_block {c with labels = ts :: c.labels} es2 ts e.at; + [I32Type] --> ts | Select -> - let t = peek 1 stack in - [t; t; I32Type] --> Stack [t] + let t = peek 1 s in + [t; t; Some I32Type] -~> [t] | Call x -> let FuncType (ins, out) = func c x in - ins --> Stack out + ins --> out | CallIndirect x -> ignore (table c (0l @@ e.at)); let FuncType (ins, out) = type_ c x in - (ins @ [I32Type]) --> Stack out + (ins @ [I32Type]) --> out | GetLocal x -> - [] --> Stack [local c x] + [] --> [local c x] | SetLocal x -> - [local c x] --> Stack [] + [local c x] --> [] | TeeLocal x -> - [local c x] --> Stack [local c x] + [local c x] --> [local c x] | GetGlobal x -> let GlobalType (t, mut) = global c x in - [] --> Stack [t] + [] --> [t] | SetGlobal x -> let GlobalType (t, mut) = global c x in require (mut = Mutable) x.at "global is immutable"; - [t] --> Stack [] + [t] --> [] | Load memop -> check_memop c memop (Lib.Option.map fst) e.at; - [I32Type] --> Stack [memop.ty] + [I32Type] --> [memop.ty] | Store memop -> check_memop c memop (fun sz -> sz) e.at; - [I32Type; memop.ty] --> Stack [] + [I32Type; memop.ty] --> [] | Const v -> let t = type_value v.it in - [] --> Stack [t] + [] --> [t] | Unary unop -> let t = type_unop unop in - [t] --> Stack [t] + [t] --> [t] | Binary binop -> let t = type_binop binop in - [t; t] --> Stack [t] + [t; t] --> [t] | Test testop -> let t = type_testop testop in - [t] --> Stack [I32Type] + [t] --> [I32Type] | Compare relop -> let t = type_relop relop in - [t; t] --> Stack [I32Type] + [t; t] --> [I32Type] | Convert cvtop -> let t1, t2 = type_cvtop e.at cvtop in - [t1] --> Stack [t2] + [t1] --> [t2] | CurrentMemory -> ignore (memory c (0l @@ e.at)); - [] --> Stack [I32Type] + [] --> [I32Type] | GrowMemory -> ignore (memory c (0l @@ e.at)); - [I32Type] --> Stack [I32Type] + [I32Type] --> [I32Type] -and check_seq (c : context) (es : instr list) : result_type = +and check_seq (c : context) (es : instr list) : infer_stack_type = match es with | [] -> - Stack [] + stack [] | _ -> let es', e = Lib.List.split_last es in - let r1 = check_seq c es' in - match r1 with - | Bot -> Bot - | Stack ts0 -> - let ts2, r2 = check_instr c e (List.rev ts0) in - let n1 = max (List.length ts0 - List.length ts2) 0 in - let ts1 = Lib.List.take n1 ts0 in - let ts2' = Lib.List.drop n1 ts0 in - if ts2 <> ts2' then result_error e.at (Stack ts2) (Stack ts2'); - match r2 with - | Bot -> Bot - | Stack ts3 -> Stack (ts1 @ ts3) + let s = check_seq c es' in + let {ins; outs} = check_instr c e s in + push outs (pop ins s e.at) and check_block (c : context) (es : instr list) (ts : stack_type) at = - check_join ts (check_seq c es) at + let s = check_seq c es in + let s' = pop (stack ts) s at in + require (snd s' = []) at + ("type mismatch: operator requires " ^ string_of_stack_type ts ^ + " but stack has " ^ string_of_infer_types (snd s')) (* Functions & Constants *) diff --git a/ml-proto/spec/types.ml b/ml-proto/spec/types.ml index 9b24818ec4..b79918bf28 100644 --- a/ml-proto/spec/types.ml +++ b/ml-proto/spec/types.ml @@ -3,7 +3,6 @@ type value_type = I32Type | I64Type | F32Type | F64Type type elem_type = AnyFuncType type stack_type = value_type list -type result_type = Stack of stack_type | Bot type func_type = FuncType of stack_type * stack_type type 'a limits = {min : 'a; max : 'a option} @@ -55,11 +54,7 @@ let string_of_global_type = function | GlobalType (t, Mutable) -> "(mut " ^ string_of_value_type t ^ ")" let string_of_stack_type ts = - "(" ^ String.concat " " (List.map string_of_value_type ts) ^ ")" - -let string_of_result_type = function - | Stack ts -> string_of_stack_type ts - | Bot -> "_|_" + "[" ^ String.concat " " (List.map string_of_value_type ts) ^ "]" let string_of_func_type (FuncType (ins, out)) = string_of_stack_type ins ^ " -> " ^ string_of_stack_type out diff --git a/ml-proto/test/block.wast b/ml-proto/test/block.wast index f1a3011e2e..c4f598facd 100644 --- a/ml-proto/test/block.wast +++ b/ml-proto/test/block.wast @@ -165,39 +165,6 @@ "type mismatch" ) -(; TODO(stack): soft failure -(assert_invalid - (module (func $type-value-num-vs-void-after-break - (block (br 0) (i32.const 1)) - )) - "type mismatch" -) -(assert_invalid - (module (func $type-value-void-vs-num-after-break (result i32) - (block (i32.const 1) (br 0) (nop)) - )) - "type mismatch" -) -(assert_invalid - (module (func $type-value-num-vs-num-after-break (result i32) - (block (i32.const 1) (br 0) (f32.const 0)) - )) - "type mismatch" -) -(assert_invalid - (module (func $type-break-second-void-vs-num (result i32) - (block i32 (br 0 (i32.const 1)) (br 0 (nop))) - )) - "type mismatch" -) -(assert_invalid - (module (func $type-break-second-num-vs-num (result i32) - (block i32 (br 0 (i32.const 1)) (br 0 (f64.const 1))) - )) - "type mismatch" -) -;) - ;; TODO(stack): move this elsewhere (module (func $type-break-num-vs-void (block (i32.const 66) (br 0)) diff --git a/ml-proto/test/br.wast b/ml-proto/test/br.wast index 2aa325f986..1c4059681e 100644 --- a/ml-proto/test/br.wast +++ b/ml-proto/test/br.wast @@ -53,10 +53,14 @@ (block (br_if 0 (br 0))) ) (func (export "as-br_if-value") (result i32) - (block i32 (br_if 0 (br 0 (i32.const 8)) (i32.const 1)) (i32.const 7)) + (block i32 + (drop (br_if 0 (br 0 (i32.const 8)) (i32.const 1))) (i32.const 7) + ) ) (func (export "as-br_if-value-cond") (result i32) - (block i32 (br_if 0 (i32.const 6) (br 0 (i32.const 9))) (i32.const 7)) + (block i32 + (drop (br_if 0 (i32.const 6) (br 0 (i32.const 9)))) (i32.const 7) + ) ) (func (export "as-br_table-index") @@ -233,7 +237,7 @@ (drop (block i32 (drop (i32.const 4)) - (br_if 0 (br 1 (i32.const 8)) (i32.const 1)) + (drop (br_if 0 (br 1 (i32.const 8)) (i32.const 1))) (i32.const 32) ) ) @@ -247,7 +251,7 @@ (i32.const 1) (block i32 (drop (i32.const 2)) - (br_if 0 (i32.const 4) (br 0 (i32.const 8))) + (drop (br_if 0 (i32.const 4) (br 0 (i32.const 8)))) (i32.const 16) ) ) @@ -376,15 +380,6 @@ (block (i32.const 0) (br 0)) )) -(; TODO(stack): soft failure -(assert_invalid - (module (func $type-arg-poly-vs-empty - (block (br 0 (unreachable))) - )) - "type mismatch" -) -;) - (assert_invalid (module (func $type-arg-void-vs-num (result i32) (block (br 0 (nop)) (i32.const 1)) diff --git a/ml-proto/test/br_if.wast b/ml-proto/test/br_if.wast index 5e2b5d5019..29e4ac7759 100644 --- a/ml-proto/test/br_if.wast +++ b/ml-proto/test/br_if.wast @@ -226,21 +226,6 @@ "type mismatch" ) -(; TODO(stack): soft failure -(assert_invalid - (module (func $type-false-arg-poly-vs-empty - (block (br_if 0 (unreachable) (i32.const 0))) - )) - "type mismatch" -) -(assert_invalid - (module (func $type-true-arg-poly-vs-empty - (block (br_if 0 (unreachable) (i32.const 1))) - )) - "type mismatch" -) -;) - (assert_invalid (module (func $type-false-arg-void-vs-num (result i32) (block i32 (br_if 0 (nop) (i32.const 0)) (i32.const 1)) diff --git a/ml-proto/test/br_table.wast b/ml-proto/test/br_table.wast index 568a25e650..365ef170ae 100644 --- a/ml-proto/test/br_table.wast +++ b/ml-proto/test/br_table.wast @@ -875,13 +875,13 @@ ) (func (export "as-br_if-value") (result i32) (block i32 - (br_if 0 (br_table 0 (i32.const 8) (i32.const 0)) (i32.const 1)) + (drop (br_if 0 (br_table 0 (i32.const 8) (i32.const 0)) (i32.const 1))) (i32.const 7) ) ) (func (export "as-br_if-value-cond") (result i32) (block i32 - (br_if 0 (i32.const 6) (br_table 0 0 (i32.const 9) (i32.const 0))) + (drop (br_if 0 (i32.const 6) (br_table 0 0 (i32.const 9) (i32.const 0)))) (i32.const 7) ) ) @@ -1142,7 +1142,12 @@ (drop (block i32 (drop (i32.const 4)) - (br_if 0 (br_table 0 1 2 (i32.const 8) (get_local 0)) (i32.const 1)) + (drop + (br_if 0 + (br_table 0 1 2 (i32.const 8) (get_local 0)) + (i32.const 1) + ) + ) (i32.const 32) ) ) @@ -1158,7 +1163,9 @@ (i32.const 1) (block i32 (drop (i32.const 2)) - (br_if 0 (i32.const 4) (br_table 0 1 0 (i32.const 8) (get_local 0))) + (drop + (br_if 0 (i32.const 4) (br_table 0 1 0 (i32.const 8) (get_local 0))) + ) (i32.const 16) ) ) @@ -1387,15 +1394,6 @@ (block (br_table 0 (i32.const 0) (i32.const 1))) )) -(; TODO(stack): soft failure -(assert_invalid - (module (func $type-arg-poly-vs-empty - (block (br_table 0 (unreachable) (i32.const 1))) - )) - "type mismatch" -) -;) - (assert_invalid (module (func $type-arg-void-vs-num (result i32) (block i32 (br_table 0 (nop) (i32.const 1)) (i32.const 1)) diff --git a/ml-proto/test/func.wast b/ml-proto/test/func.wast index 386a9864f2..03c23c089e 100644 --- a/ml-proto/test/func.wast +++ b/ml-proto/test/func.wast @@ -511,15 +511,6 @@ "type mismatch" ) -(; TODO(stack): soft failure -(assert_invalid - (module (func $type-break-second-num-vs-num (result i32) - (br 0 (i32.const 1)) (br 0 (f64.const 1)) - )) - "type mismatch" -) -;) - (assert_invalid (module (func $type-break-nested-empty-vs-num (result i32) (block (br 1)) (br 0 (i32.const 1)) diff --git a/ml-proto/test/loop.wast b/ml-proto/test/loop.wast index df5ad57f3e..c1686d8201 100644 --- a/ml-proto/test/loop.wast +++ b/ml-proto/test/loop.wast @@ -252,21 +252,6 @@ "type mismatch" ) -(; TODO(stack): soft failure -(assert_invalid - (module (func $type-value-void-vs-num-after-break (result i32) - (loop (br 1 (i32.const 1)) (nop)) - )) - "type mismatch" -) -(assert_invalid - (module (func $type-value-num-vs-num-after-break (result i32) - (loop (br 1 (i32.const 1)) (f32.const 0)) - )) - "type mismatch" -) -;) - (assert_invalid (module (func $type-cont-last-void-vs-empty (result i32) (loop (br 0 (nop))) diff --git a/ml-proto/test/return.wast b/ml-proto/test/return.wast index e092b26210..a16d141814 100644 --- a/ml-proto/test/return.wast +++ b/ml-proto/test/return.wast @@ -56,10 +56,14 @@ (block (br_if 0 (return))) ) (func (export "as-br_if-value") (result i32) - (block i32 (br_if 0 (return (i32.const 8)) (i32.const 1)) (i32.const 7)) + (block i32 + (drop (br_if 0 (return (i32.const 8)) (i32.const 1))) (i32.const 7) + ) ) (func (export "as-br_if-value-cond") (result i32) - (block i32 (br_if 0 (i32.const 6) (return (i32.const 9))) (i32.const 7)) + (block i32 + (drop (br_if 0 (i32.const 6) (return (i32.const 9)))) (i32.const 7) + ) ) (func (export "as-br_table-index") (result i64) @@ -81,7 +85,7 @@ ) (func (export "as-if-cond") (result i32) - (if (return (i32.const 2)) (i32.const 0) (i32.const 1)) + (if i32 (return (i32.const 2)) (i32.const 0) (i32.const 1)) ) (func (export "as-if-then") (param i32 i32) (result i32) (if i32 (get_local 0) (return (i32.const 3)) (get_local 1)) diff --git a/ml-proto/test/soft-fail.wast b/ml-proto/test/soft-fail.wast new file mode 100644 index 0000000000..6cf00b458d --- /dev/null +++ b/ml-proto/test/soft-fail.wast @@ -0,0 +1,226 @@ +;; Test soft failures +;; These are invalid Wasm, but the failure is in dead code, which +;; implementations are not required to validate. If they do, they shall diagnose +;; the correct error. + +(assert_soft_invalid + (module (func $type-num-vs-num + (unreachable) (drop (i64.eqz (i32.const 0)))) + ) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-poly-num-vs-num (result i32) + (unreachable) (i64.const 0) (i32.const 0) (select) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-poly-transitive-num-vs-num (result i32) + (unreachable) + (i64.const 0) (i32.const 0) (select) + (i32.const 0) (i32.const 0) (select) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-unconsumed-const (unreachable) (i32.const 0))) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-unconsumed-result (unreachable) (i32.eqz))) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-unconsumed-result2 (unreachable) (i32.const 0) (i32.add))) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-unconsumed-poly0 (unreachable) (select))) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-unconsumed-poly1 (unreachable) (i32.const 0) (select))) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-unconsumed-poly2 + (unreachable) (i32.const 0) (i32.const 0) (select) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-block-value-num-vs-void-after-break + (block (br 0) (i32.const 1)) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-num-vs-num-after-break (result i32) + (block i32 (i32.const 1) (br 0) (f32.const 0)) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-loop-value-num-vs-void-after-break + (block (loop (br 1) (i32.const 1))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-loop-value-num-vs-num-after-break (result i32) + (loop i32 (br 1 (i32.const 1)) (f32.const 0)) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-func-value-num-vs-void-after-break + (br 0) (i32.const 1) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-func-value-num-vs-num-after-break (result i32) + (br 0 (i32.const 1)) (f32.const 0) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-br-second-num-vs-num (result i32) + (block i32 (br 0 (i32.const 1)) (br 0 (f64.const 1))) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-br_if-cond-num-vs-num + (block (br_if 0 (unreachable) (f32.const 0))) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-br_table-num-vs-num + (block (br_table 0 (unreachable) (f32.const 1))) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-block-value-nested-unreachable-num-vs-void + (block (i32.const 3) (block (unreachable))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-nested-unreachable-void-vs-num (result i32) + (block (block (unreachable))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-nested-unreachable-num-vs-num (result i32) + (block i64 (i64.const 0) (block (unreachable))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-nested-unreachable-num2-vs-void (result i32) + (block (i32.const 3) (block (i64.const 1) (unreachable))) (i32.const 9) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-block-value-nested-br-num-vs-void + (block (i32.const 3) (block (br 1))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-nested-br-void-vs-num (result i32) + (block i32 (block (br 1 (i32.const 0)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-nested-br-num-vs-num (result i32) + (block i32 (i64.const 0) (block (br 1 (i32.const 0)))) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-block-value-nested2-br-num-vs-void + (block (block (i32.const 3) (block (br 2)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-nested2-br-void-vs-num (result i32) + (block i32 (block (block (br 2 (i32.const 0))))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-nested2-br-num-vs-num (result i32) + (block i32 (block i64 (i64.const 0) (block (br 2 (i32.const 0))))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-nested2-br-num2-vs-void (result i32) + (block (i32.const 3) (block (i64.const 1) (br 1))) (i32.const 9) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-block-value-nested-return-num-vs-void + (block (i32.const 3) (block (return))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-nested-return-void-vs-num (result i32) + (block (block (return (i32.const 0)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-nested-return-num-vs-num (result i32) + (block i64 (i64.const 0) (block (return (i32.const 0)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-nested-return-num2-vs-void (result i32) + (block (i32.const 3) (block (i64.const 1) (return (i32.const 0)))) + (i32.const 9) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-loop-value-nested-unreachable-num-vs-void + (loop (i32.const 3) (block (unreachable))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-loop-value-nested-unreachable-void-vs-num (result i32) + (loop (block (unreachable))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-loop-value-nested-unreachable-num-vs-num (result i32) + (loop i64 (i64.const 0) (block (unreachable))) + )) + "type mismatch" +) diff --git a/ml-proto/test/unreachable.wast b/ml-proto/test/unreachable.wast index f7cd8dcbcf..82efa8fad7 100644 --- a/ml-proto/test/unreachable.wast +++ b/ml-proto/test/unreachable.wast @@ -60,10 +60,10 @@ (block (br_if 0 (unreachable))) ) (func (export "as-br_if-value") (result i32) - (block i32 (br_if 0 (unreachable) (i32.const 1)) (i32.const 7)) + (block i32 (drop (br_if 0 (unreachable) (i32.const 1))) (i32.const 7)) ) (func (export "as-br_if-value-cond") (result i32) - (block i32 (br_if 0 (i32.const 6) (unreachable)) (i32.const 7)) + (block i32 (drop (br_if 0 (i32.const 6) (unreachable))) (i32.const 7)) ) (func (export "as-br_table-index") @@ -81,7 +81,7 @@ ) (func (export "as-if-cond") (result i32) - (if (unreachable) (i32.const 0) (i32.const 1)) + (if i32 (unreachable) (i32.const 0) (i32.const 1)) ) (func (export "as-if-then") (param i32 i32) (result i32) (if i32 (get_local 0) (unreachable) (get_local 1)) From 808a44456e1f9dac1cd9a781be234e868f6d29d8 Mon Sep 17 00:00:00 2001 From: rossberg-chromium Date: Mon, 10 Oct 2016 11:26:50 +0200 Subject: [PATCH 2/5] Remove obsolete test --- ml-proto/test/typecheck.wast | 8 -------- 1 file changed, 8 deletions(-) diff --git a/ml-proto/test/typecheck.wast b/ml-proto/test/typecheck.wast index 444e0556df..1d15cc5675 100644 --- a/ml-proto/test/typecheck.wast +++ b/ml-proto/test/typecheck.wast @@ -157,14 +157,6 @@ )) "type mismatch" ) -(assert_invalid - (module (func $type-br-operand-missing-in-loop - (i32.const 0) - (loop i32 (br 0)) - (i32.eqz) (drop) - )) - "type mismatch" -) (assert_invalid (module (func $type-br-operand-missing-in-if (block From d6e139c0f74e17ead94b148cf8ffed1ba762ca3c Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 11 Oct 2016 14:51:20 +0200 Subject: [PATCH 3/5] Address a couple of more test TODOs --- ml-proto/test/func.wast | 39 ------------------------------------ ml-proto/test/return.wast | 4 ---- ml-proto/test/soft-fail.wast | 18 +++++++++++++++++ ml-proto/test/unwind.wast | 26 ++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 43 deletions(-) diff --git a/ml-proto/test/func.wast b/ml-proto/test/func.wast index 5879ab718f..a9c71db480 100644 --- a/ml-proto/test/func.wast +++ b/ml-proto/test/func.wast @@ -392,37 +392,6 @@ "type mismatch" ) -(; TODO(stack): Should these become legal? -(assert_invalid - (module (func $type-value-void-vs-num-after-return (result i32) - (return (i32.const 1)) (nop) - )) - "type mismatch" -) -(assert_invalid - (module (func $type-value-num-vs-num-after-return (result i32) - (return (i32.const 1)) (f32.const 0) - )) - "type mismatch" -) -(assert_invalid - (module (func $type-value-void-vs-num-after-break (result i32) - (br 0 (i32.const 1)) (nop) - )) - "type mismatch" -) -(assert_invalid - (module (func $type-value-num-vs-num-after-break (result i32) - (br 0 (i32.const 1)) (f32.const 0) - )) - "arity mismatch" -) -;) - -;; TODO(stack): move these somewhere else -(module (func $type-return-void-vs-enpty (return (nop)))) -(module (func $type-return-num-vs-enpty (return (i32.const 0)))) - (assert_invalid (module (func $type-return-last-empty-vs-num (result i32) (return) @@ -466,14 +435,6 @@ )) "type mismatch" ) -(; TODO(stack): Should this become legal? -(assert_invalid - (module (func $type-return-second-num-vs-num (result i32) - (return (i32.const 1)) (return (f64.const 1)) - )) - "type mismatch" -) -;) (assert_invalid (module (func $type-break-last-void-vs-num (result i32) diff --git a/ml-proto/test/return.wast b/ml-proto/test/return.wast index a16d141814..60db41c1f1 100644 --- a/ml-proto/test/return.wast +++ b/ml-proto/test/return.wast @@ -266,10 +266,6 @@ (assert_return (invoke "as-grow_memory-size") (i32.const 40)) -;; TODO(stack): move these somewhere else -(module (func $type-value-void-vs-empty (return (nop)))) -(module (func $type-value-num-vs-empty (return (i32.const 0)))) - (assert_invalid (module (func $type-value-empty-vs-num (result f64) (return))) "type mismatch" diff --git a/ml-proto/test/soft-fail.wast b/ml-proto/test/soft-fail.wast index 6cf00b458d..4608bcd386 100644 --- a/ml-proto/test/soft-fail.wast +++ b/ml-proto/test/soft-fail.wast @@ -89,6 +89,24 @@ )) "type mismatch" ) +(assert_soft_invalid + (module (func $type-func-value-num-vs-void-after-return + (return) (i32.const 1) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-func-value-num-vs-num-after-return (result i32) + (return (i32.const 1)) (f32.const 0) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-return-second-num-vs-num (result i32) + (return (i32.const 1)) (return (f64.const 1)) + )) + "type mismatch" +) (assert_soft_invalid (module (func $type-br-second-num-vs-num (result i32) diff --git a/ml-proto/test/unwind.wast b/ml-proto/test/unwind.wast index 8db16c75bd..b993f2a873 100644 --- a/ml-proto/test/unwind.wast +++ b/ml-proto/test/unwind.wast @@ -1,6 +1,25 @@ ;; Test that control-flow transfer unwinds stack and it can be anything after. (module + (func (export "func-unwind-by-unreachable") + (i32.const 3) (i64.const 1) (unreachable) + ) + (func (export "func-unwind-by-br") + (i32.const 3) (i64.const 1) (br 0) + ) + (func (export "func-unwind-by-br-value") (result i32) + (i32.const 3) (i64.const 1) (br 0 (i32.const 9)) + ) + (func (export "func-unwind-by-br_table") + (i32.const 3) (i64.const 1) (br_table 0 (i32.const 0)) + ) + (func (export "func-unwind-by-br_table-value") (result i32) + (i32.const 3) (i64.const 1) (br_table 0 (i32.const 9) (i32.const 0)) + ) + (func (export "func-unwind-by-return") (result i32) + (i32.const 3) (i64.const 1) (return (i32.const 9)) + ) + (func (export "block-unwind-by-unreachable") (block (i32.const 3) (i64.const 1) (unreachable)) ) @@ -127,6 +146,13 @@ ) ) +(assert_trap (invoke "func-unwind-by-unreachable") "unreachable") +(assert_return (invoke "func-unwind-by-br")) +(assert_return (invoke "func-unwind-by-br-value") (i32.const 9)) +(assert_return (invoke "func-unwind-by-br_table")) +(assert_return (invoke "func-unwind-by-br_table-value") (i32.const 9)) +(assert_return (invoke "func-unwind-by-return") (i32.const 9)) + (assert_trap (invoke "block-unwind-by-unreachable") "unreachable") (assert_return (invoke "block-unwind-by-br") (i32.const 9)) (assert_return (invoke "block-unwind-by-br-value") (i32.const 9)) From 2e2ef17595394dce9ab557177b6ead3c3e695cc2 Mon Sep 17 00:00:00 2001 From: rossberg-chromium Date: Thu, 13 Oct 2016 16:16:05 +0200 Subject: [PATCH 4/5] Mo tests --- ml-proto/test/soft-fail.wast | 275 ++++++++++++++++++++++++++++++++++- 1 file changed, 267 insertions(+), 8 deletions(-) diff --git a/ml-proto/test/soft-fail.wast b/ml-proto/test/soft-fail.wast index 4608bcd386..9eb072cfde 100644 --- a/ml-proto/test/soft-fail.wast +++ b/ml-proto/test/soft-fail.wast @@ -1,7 +1,7 @@ ;; Test soft failures ;; These are invalid Wasm, but the failure is in dead code, which -;; implementations are not required to validate. If they do, they shall diagnose -;; the correct error. +;; implementations are not required to validate. If they do, they shall +;; diagnose the correct error. (assert_soft_invalid (module (func $type-num-vs-num @@ -33,7 +33,9 @@ "type mismatch" ) (assert_soft_invalid - (module (func $type-unconsumed-result2 (unreachable) (i32.const 0) (i32.add))) + (module (func $type-unconsumed-result2 + (unreachable) (i32.const 0) (i32.add) + )) "type mismatch" ) (assert_soft_invalid @@ -51,6 +53,30 @@ "type mismatch" ) +(assert_soft_invalid + (module (func $type-unary-num-vs-void-after-break + (block (br 0) (block (drop (i32.eqz (nop))))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-unary-num-vs-num-after-break + (block (br 0) (drop (i32.eqz (f32.const 1)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-binary-num-vs-void-after-break + (block (br 0) (block (drop (f32.eq (i32.const 1))))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-binary-num-vs-num-after-break + (block (br 0) (drop (f32.eq (i32.const 1) (f32.const 0)))) + )) + "type mismatch" +) (assert_soft_invalid (module (func $type-block-value-num-vs-void-after-break (block (br 0) (i32.const 1)) @@ -63,7 +89,6 @@ )) "type mismatch" ) - (assert_soft_invalid (module (func $type-loop-value-num-vs-void-after-break (block (loop (br 1) (i32.const 1))) @@ -76,7 +101,6 @@ )) "type mismatch" ) - (assert_soft_invalid (module (func $type-func-value-num-vs-void-after-break (br 0) (i32.const 1) @@ -89,6 +113,55 @@ )) "type mismatch" ) + +(assert_soft_invalid + (module (func $type-unary-num-vs-void-after-return + (return) (block (drop (i32.eqz (nop)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-unary-num-vs-num-after-return + (return) (drop (i32.eqz (f32.const 1))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-binary-num-vs-void-after-return + (return) (block (drop (f32.eq (i32.const 1)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-binary-num-vs-num-after-return + (return) (drop (f32.eq (i32.const 1) (f32.const 0))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-num-vs-void-after-return + (block (return) (i32.const 1)) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-num-vs-num-after-return (result i32) + (block i32 (i32.const 1) (return (i32.const 0)) (f32.const 0)) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-loop-value-num-vs-void-after-return + (block (loop (return) (i32.const 1))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-loop-value-num-vs-num-after-return (result i32) + (loop i32 (return (i32.const 1)) (f32.const 0)) + )) + "type mismatch" +) (assert_soft_invalid (module (func $type-func-value-num-vs-void-after-return (return) (i32.const 1) @@ -101,6 +174,193 @@ )) "type mismatch" ) + +(assert_soft_invalid + (module (func $type-unary-num-vs-void-after-unreachable + (unreachable) (block (drop (i32.eqz (nop)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-unary-num-vs-num-after-unreachable + (unreachable) (drop (i32.eqz (f32.const 1))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-binary-num-vs-void-after-unreachable + (unreachable) (block (drop (f32.eq (i32.const 1)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-binary-num-vs-num-after-unreachable + (unreachable) (drop (f32.eq (i32.const 1) (f32.const 0))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-num-vs-void-after-unreachable + (block (unreachable) (i32.const 1)) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-num-vs-num-after-unreachable (result i32) + (block i32 (i32.const 1) (unreachable) (f32.const 0)) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-loop-value-num-vs-void-after-unreachable + (block (loop (unreachable) (i32.const 1))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-loop-value-num-vs-num-after-unreachable (result i32) + (loop i32 (unreachable) (f32.const 0)) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-func-value-num-vs-void-after-unreachable + (unreachable) (i32.const 1) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-func-value-num-vs-num-after-unreachable (result i32) + (unreachable) (f32.const 0) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-unary-num-vs-void-after-nested-unreachable + (block (unreachable)) (block (drop (i32.eqz (nop)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-unary-num-vs-num-after-nested-unreachable + (block (unreachable)) (drop (i32.eqz (f32.const 1))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-binary-num-vs-void-after-nested-unreachable + (block (unreachable)) (block (drop (f32.eq (i32.const 1)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-binary-num-vs-num-after-nested-unreachable + (block (unreachable)) (drop (f32.eq (i32.const 1) (f32.const 0))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-num-vs-void-after-nested-unreachable + (block (block (unreachable)) (i32.const 1)) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-num-vs-num-after-nested-unreachable + (result i32) + (block i32 (i32.const 1) (block (unreachable)) (f32.const 0)) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-loop-value-num-vs-void-after-nested-unreachable + (block (loop (block (unreachable)) (i32.const 1))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-loop-value-num-vs-num-after-nested-unreachable + (result i32) + (loop i32 (block (unreachable)) (f32.const 0)) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-func-value-num-vs-void-after-nested-unreachable + (block (unreachable)) (i32.const 1) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-func-value-num-vs-num-after-nested-unreachable + (result i32) + (block (unreachable)) (f32.const 0) + )) + "type mismatch" +) + +(assert_soft_invalid + (module (func $type-unary-num-vs-void-after-infinite-loop + (loop (br 0)) (block (drop (i32.eqz (nop)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-unary-num-vs-num-after-infinite-loop + (loop (br 0)) (drop (i32.eqz (f32.const 1))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-binary-num-vs-void-after-infinite-loop + (loop (br 0)) (block (drop (f32.eq (i32.const 1)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-binary-num-vs-num-after-infinite-loop + (loop (br 0)) (drop (f32.eq (i32.const 1) (f32.const 0))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-num-vs-void-after-infinite-loop + (block (loop (br 0)) (i32.const 1)) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-num-vs-num-after-infinite-loop (result i32) + (block i32 (i32.const 1) (loop (br 0)) (f32.const 0)) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-loop-value-num-vs-void-after-infinite-loop + (block (loop (loop (br 0)) (i32.const 1))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-loop-value-num-vs-num-after-infinite-loop (result i32) + (loop i32 (loop (br 0)) (f32.const 0)) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-func-value-num-vs-void-after-infinite-loop + (loop (br 0)) (i32.const 1) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-func-value-num-vs-num-after-infinite-loop (result i32) + (loop (br 0)) (f32.const 0) + )) + "type mismatch" +) + (assert_soft_invalid (module (func $type-return-second-num-vs-num (result i32) (return (i32.const 1)) (return (f64.const 1)) @@ -116,14 +376,13 @@ ) (assert_soft_invalid - (module (func $type-br_if-cond-num-vs-num + (module (func $type-br_if-cond-num-vs-num-after-unreachable (block (br_if 0 (unreachable) (f32.const 0))) )) "type mismatch" ) - (assert_soft_invalid - (module (func $type-br_table-num-vs-num + (module (func $type-br_table-num-vs-num-after-unreachable (block (br_table 0 (unreachable) (f32.const 1))) )) "type mismatch" From a7d6135ace925420713a031d418bab237cfc5532 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sat, 15 Oct 2016 16:06:47 +0200 Subject: [PATCH 5/5] Mo tests 2 --- ml-proto/test/soft-fail.wast | 61 ++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/ml-proto/test/soft-fail.wast b/ml-proto/test/soft-fail.wast index 9eb072cfde..7750ddd1a2 100644 --- a/ml-proto/test/soft-fail.wast +++ b/ml-proto/test/soft-fail.wast @@ -361,6 +361,67 @@ "type mismatch" ) +(assert_soft_invalid + (module (func $type-unary-num-vs-void-in-dead-body + (if (i32.const 0) (then (drop (i32.eqz (nop))))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-unary-num-vs-num-in-dead-body + (if (i32.const 0) (then (drop (i32.eqz (f32.const 1))))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-binary-num-vs-void-in-dead-body + (if (i32.const 0) (then (drop (f32.eq (i32.const 1))))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-binary-num-vs-num-in-dead-body + (if (i32.const 0) (then (drop (f32.eq (i32.const 1) (f32.const 0))))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-if-value-num-vs-void-in-dead-body + (if (i32.const 0) (then (i32.const 1))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-if-value-num-vs-num-in-dead-body (result i32) + (if i32 (i32.const 0) (then (f32.const 0))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-num-vs-void-in-dead-body + (if (i32.const 0) (then (block (i32.const 1)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-num-vs-num-in-dead-body (result i32) + (if i32 (i32.const 0) (then (block i32 (f32.const 0)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-num-vs-void-in-dead-body + (if (i32.const 0) (then (loop (i32.const 1)))) + )) + "type mismatch" +) +(assert_soft_invalid + (module (func $type-block-value-num-vs-num-in-dead-body (result i32) + (if i32 (i32.const 0) (then (loop i32 (f32.const 0)))) + )) + "type mismatch" +) + (assert_soft_invalid (module (func $type-return-second-num-vs-num (result i32) (return (i32.const 1)) (return (f64.const 1))