From 8c5caa251bfe1a7fd862f7302bb51ca21b310444 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Wed, 16 Sep 2015 22:42:42 -0500 Subject: [PATCH] Add assert_fault script command --- ml-proto/README.md | 9 +++++---- ml-proto/src/host/lexer.mll | 1 + ml-proto/src/host/parser.mly | 4 +++- ml-proto/src/host/print.ml | 2 +- ml-proto/src/host/script.ml | 27 ++++++++++++++++++++------- ml-proto/src/host/script.mli | 1 + ml-proto/test/memory_fault.wasm | 18 ++++++++++++++++++ 7 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 ml-proto/test/memory_fault.wasm diff --git a/ml-proto/README.md b/ml-proto/README.md index 0b2c6aad47..53e441a3ae 100644 --- a/ml-proto/README.md +++ b/ml-proto/README.md @@ -226,10 +226,11 @@ In order to be able to check and run modules for testing purposes, the S-express script: * cmd: - ;; define, validate, and initialize module - ( invoke * ) ;; invoke export and print result - ( assert_eq (invoke * ) ) ;; assert expected results of invocation - ( assert_invalid ) ;; assert invalid module with given failure string + ;; define, validate, and initialize module + ( invoke * ) ;; invoke export and print result + ( assert_eq (invoke * ) ) ;; assert expected results of invocation + ( assert_fault (invoke * ) ) ;; assert invocation faults with given failure string + ( assert_invalid ) ;; assert invalid module with given failure string ``` Invocation is only possible after a module has been defined. diff --git a/ml-proto/src/host/lexer.mll b/ml-proto/src/host/lexer.mll index 1682b8a67d..6d7bd75663 100644 --- a/ml-proto/src/host/lexer.mll +++ b/ml-proto/src/host/lexer.mll @@ -249,6 +249,7 @@ rule token = parse | "assert_invalid" { ASSERTINVALID } | "assert_eq" { ASSERTEQ } + | "assert_fault" { ASSERTFAULT } | "invoke" { INVOKE } | name as s { VAR s } diff --git a/ml-proto/src/host/parser.mly b/ml-proto/src/host/parser.mly index abaaa50f41..35ca13d224 100644 --- a/ml-proto/src/host/parser.mly +++ b/ml-proto/src/host/parser.mly @@ -103,7 +103,7 @@ let anon_label c = {c with labels = VarMap.map ((+) 1) c.labels} %token GETLOCAL SETLOCAL LOADGLOBAL STOREGLOBAL LOAD STORE %token CONST UNARY BINARY COMPARE CONVERT %token FUNC PARAM RESULT LOCAL MODULE MEMORY SEGMENT GLOBAL IMPORT EXPORT TABLE -%token ASSERTINVALID ASSERTEQ INVOKE +%token ASSERTINVALID ASSERTEQ ASSERTFAULT INVOKE %token EOF %token INT @@ -348,6 +348,8 @@ cmd : { Invoke ($3, $4 (c0 ())) @@ at() } | LPAR ASSERTEQ LPAR INVOKE TEXT expr_list RPAR expr RPAR { AssertEq ($5, $6 (c0 ()), $8 (c0 ())) @@ at() } + | LPAR ASSERTFAULT LPAR INVOKE TEXT expr_list RPAR TEXT RPAR + { AssertFault ($5, $6 (c0 ()), $8) @@ at() } ; cmd_list : | /* empty */ { [] } diff --git a/ml-proto/src/host/print.ml b/ml-proto/src/host/print.ml index cf69068628..9ee8f238ac 100644 --- a/ml-proto/src/host/print.ml +++ b/ml-proto/src/host/print.ml @@ -73,6 +73,6 @@ let print_value vo = (Values.string_of_value v) (Types.string_of_value_type t); flush_all () | None -> - printf "()"; + printf "()\n"; flush_all () diff --git a/ml-proto/src/host/script.ml b/ml-proto/src/host/script.ml index 238c7251eb..20c78dd341 100644 --- a/ml-proto/src/host/script.ml +++ b/ml-proto/src/host/script.ml @@ -12,6 +12,7 @@ and command' = | AssertInvalid of Ast.modul * string | Invoke of string * Ast.expr list | AssertEq of string * Ast.expr list * Ast.expr + | AssertFault of string * Ast.expr list * string type script = command list @@ -29,6 +30,14 @@ let eval_args es at = | None -> Error.error at "unexpected () value" in List.map reject_none evs +let assert_error f err re at = + match try f (); None with Error.Error (_, s) -> Some s with + | None -> + Error.error at ("expected " ^ err) + | Some s -> + if not (Str.string_match (Str.regexp re) s 0) then + Error.error at ("failure \"" ^ s ^ "\" does not match: \"" ^ re ^ "\"") + let run_command cmd = match cmd.it with | Define m -> @@ -44,13 +53,7 @@ let run_command cmd = | AssertInvalid (m, re) -> trace "Checking invalid..."; - (match try Check.check_module m; None with Error.Error (_, s) -> Some s with - | None -> - Error.error cmd.at "expected invalid module" - | Some s -> - if not (Str.string_match (Str.regexp re) s 0) then - Error.error cmd.at - ("validation failure \"" ^ s ^ "\" does not match: \"" ^ re ^ "\"")) + assert_error (fun () -> Check.check_module m) "invalid module" re cmd.at | Invoke (name, es) -> trace "Invoking..."; @@ -79,6 +82,15 @@ let run_command cmd = Error.error cmd.at "assertion failed" end + | AssertFault (name, es, re) -> + trace "Assert fault invoking..."; + let m = match !current_module with + | Some m -> m + | None -> Error.error cmd.at "no module defined to invoke" + in + let vs = eval_args es cmd.at in + assert_error (fun () -> Eval.invoke m name vs) "fault" re cmd.at + let dry_command cmd = match cmd.it with | Define m -> @@ -87,6 +99,7 @@ let dry_command cmd = | AssertInvalid _ -> () | Invoke _ -> () | AssertEq _ -> () + | AssertFault _ -> () let run script = List.iter (if !Flags.dry then dry_command else run_command) script diff --git a/ml-proto/src/host/script.mli b/ml-proto/src/host/script.mli index 18ddf5cc70..7967d23b8d 100644 --- a/ml-proto/src/host/script.mli +++ b/ml-proto/src/host/script.mli @@ -8,6 +8,7 @@ and command' = | AssertInvalid of Ast.modul * string | Invoke of string * Ast.expr list | AssertEq of string * Ast.expr list * Ast.expr + | AssertFault of string * Ast.expr list * string type script = command list diff --git a/ml-proto/test/memory_fault.wasm b/ml-proto/test/memory_fault.wasm new file mode 100644 index 0000000000..1c85b373b1 --- /dev/null +++ b/ml-proto/test/memory_fault.wasm @@ -0,0 +1,18 @@ +(module + (memory 100) + + (export "store" $store) + (func $store (param $i i32) (param $v i32) (i32.store (get_local $i) (get_local $v))) + + (export "load" $load) + (func $load (param $i i32) (result i32) (i32.load (get_local $i))) +) + +(invoke "store" (i32.const 96) (i32.const 42)) +(assert_eq (invoke "load" (i32.const 96)) (i32.const 42)) +(assert_fault (invoke "store" (i32.const 97) (i32.const 13)) "runtime: out of bounds memory access") +(assert_fault (invoke "load" (i32.const 97)) "runtime: out of bounds memory access") +(assert_fault (invoke "store" (i32.const 98) (i32.const 13)) "runtime: out of bounds memory access") +(assert_fault (invoke "load" (i32.const 98)) "runtime: out of bounds memory access") +(assert_fault (invoke "store" (i32.const 99) (i32.const 13)) "runtime: out of bounds memory access") +(assert_fault (invoke "load" (i32.const 99)) "runtime: out of bounds memory access")