diff --git a/ml-proto/host/builtins.ml b/ml-proto/host/builtins.ml index 922472a750..61619cbdb7 100644 --- a/ml-proto/host/builtins.ml +++ b/ml-proto/host/builtins.ml @@ -2,6 +2,9 @@ open Source open Types open Ast +module Unknown = Error.Make () +exception Unknown = Unknown.Error (* indicates unknown import name *) + let print vs = List.iter Print.print_value (List.map (fun v -> Some v) vs); None @@ -10,14 +13,14 @@ let match_import m i = let {module_name; func_name; itype} = i.it in let {ins; out} = List.nth m.it.types itype.it in if module_name <> "stdio" then - Error.error i.at ("no builtin module \"" ^ module_name ^ "\""); + Unknown.error i.at ("no module \"" ^ module_name ^ "\""); match func_name with | "print" -> if out <> None then - Error.error i.at "stdio.print has no result"; + Unknown.error i.at "stdio.print has no result"; print | _ -> - Error.error i.at ("no \"stdio." ^ func_name ^ "\"") + Unknown.error i.at ("no function \"stdio." ^ func_name ^ "\"") let match_imports m = List.map (match_import m) m.it.imports diff --git a/ml-proto/host/builtins.mli b/ml-proto/host/builtins.mli index 9794db4d7c..36d8d9db71 100644 --- a/ml-proto/host/builtins.mli +++ b/ml-proto/host/builtins.mli @@ -1 +1,3 @@ -val match_imports : Ast.module_ -> Eval.import list +exception Unknown of Source.region * string + +val match_imports : Ast.module_ -> Eval.import list (* raises Unknown *) diff --git a/ml-proto/host/lexer.mll b/ml-proto/host/lexer.mll index cf3ea9542e..5fdaaf5ef1 100644 --- a/ml-proto/host/lexer.mll +++ b/ml-proto/host/lexer.mll @@ -17,10 +17,10 @@ let region lexbuf = let right = convert_pos (Lexing.lexeme_end_p lexbuf) in {Source.left = left; Source.right = right} -let error lexbuf m = Error.error (region lexbuf) m -let error_nest start lexbuf m = +let error lexbuf msg = raise (Script.Syntax (region lexbuf, msg)) +let error_nest start lexbuf msg = lexbuf.Lexing.lex_start_p <- start; - error lexbuf m + error lexbuf msg let convert_text s = let b = Buffer.create (String.length s) in diff --git a/ml-proto/host/main.ml b/ml-proto/host/main.ml index 33060f86e6..a126d76dbe 100644 --- a/ml-proto/host/main.ml +++ b/ml-proto/host/main.ml @@ -22,11 +22,16 @@ let parse name source = let lexbuf = Lexing.from_string source in lexbuf.Lexing.lex_curr_p <- {lexbuf.Lexing.lex_curr_p with Lexing.pos_fname = name}; - try Parser.script Lexer.token lexbuf with Error.Error (region, s) -> + try Parser.script Lexer.token lexbuf with Script.Syntax (region, s) -> let region' = if region <> Source.no_region then region else {Source.left = Lexer.convert_pos lexbuf.Lexing.lex_start_p; Source.right = Lexer.convert_pos lexbuf.Lexing.lex_curr_p} in - raise (Error.Error (region', s)) + raise (Script.Syntax (region', s)) + +let error at category msg = + Script.trace ("Error (" ^ category ^ "): "); + prerr_endline (Source.string_of_region at ^ ": " ^ msg); + false let process file source = try @@ -35,10 +40,13 @@ let process file source = Script.trace "Running..."; Script.run script; true - with Error.Error (at, s) -> - Script.trace "Error:"; - prerr_endline (Source.string_of_region at ^ ": " ^ s); - false + with + | Script.Syntax (at, msg) -> error at "syntax error" msg + | Script.AssertFailure (at, msg) -> error at "assertion failure" msg + | Check.Invalid (at, msg) -> error at "invalid module" msg + | Eval.Trap (at, msg) -> error at "runtime trap" msg + | Eval.Crash (at, msg) -> error at "runtime crash" msg + | Builtins.Unknown (at, msg) -> error at "unknown built-in" msg let process_file file = Script.trace ("Loading (" ^ file ^ ")..."); diff --git a/ml-proto/host/parser.mly b/ml-proto/host/parser.mly index ef65c68700..ab9894bd7f 100644 --- a/ml-proto/host/parser.mly +++ b/ml-proto/host/parser.mly @@ -10,6 +10,13 @@ open Types open Script +(* Error handling *) + +let error at msg = raise (Script.Syntax (at, msg)) + +let parse_error msg = error Source.no_region msg + + (* Position handling *) let position_to_pos position = @@ -28,8 +35,6 @@ let at () = let ati i = positions_to_region (Parsing.rhs_start_pos i) (Parsing.rhs_end_pos i) -let parse_error s = Error.error Source.no_region s - (* Literals *) @@ -41,8 +46,8 @@ let literal s t = | Float32Type -> Values.Float32 (F32.of_string s.it) @@ s.at | Float64Type -> Values.Float64 (F64.of_string s.it) @@ s.at with - | Failure reason -> Error.error s.at ("constant out of range: " ^ reason) - | _ -> Error.error s.at "constant out of range" + | Failure msg -> error s.at ("constant out of range: " ^ msg) + | _ -> error s.at "constant out of range" (* Memory operands *) @@ -87,28 +92,28 @@ let enter_func c = let type_ c x = try VarMap.find x.it c.types.tmap - with Not_found -> Error.error x.at ("unknown type " ^ x.it) + with Not_found -> error x.at ("unknown type " ^ x.it) let lookup category space x = try VarMap.find x.it space.map - with Not_found -> Error.error x.at ("unknown " ^ category ^ " " ^ x.it) + with Not_found -> error x.at ("unknown " ^ category ^ " " ^ x.it) let func c x = lookup "function" c.funcs x let import c x = lookup "import" c.imports x let local c x = lookup "local" c.locals x let label c x = try VarMap.find x.it c.labels - with Not_found -> Error.error x.at ("unknown label " ^ x.it) + with Not_found -> error x.at ("unknown label " ^ x.it) let bind_type c x ty = if VarMap.mem x.it c.types.tmap then - Error.error x.at ("duplicate type " ^ x.it); + error x.at ("duplicate type " ^ x.it); c.types.tmap <- VarMap.add x.it (List.length c.types.tlist) c.types.tmap; c.types.tlist <- c.types.tlist @ [ty] let bind category space x = if VarMap.mem x.it space.map then - Error.error x.at ("duplicate " ^ category ^ " " ^ x.it); + error x.at ("duplicate " ^ category ^ " " ^ x.it); space.map <- VarMap.add x.it space.count space.map; space.count <- space.count + 1 @@ -132,10 +137,12 @@ let empty_type = {ins = []; out = None} let explicit_decl c name t at = let x = name c type_ in - if x.it < List.length c.types.tlist && - t <> empty_type && - t <> List.nth c.types.tlist x.it then - Error.error at "signature mismatch"; + if + x.it < List.length c.types.tlist && + t <> empty_type && + t <> List.nth c.types.tlist x.it + then + error at "signature mismatch"; x let implicit_decl c t at = @@ -323,8 +330,7 @@ func_fields : { {(fst $6) with ins = $4 :: (fst $6).ins}, fun c -> bind_local c $3; (snd $6) c } | LPAR RESULT VALUE_TYPE RPAR func_fields - { if (fst $5).out <> None then - Error.error (at ()) "more than one return type"; + { if (fst $5).out <> None then error (at ()) "multiple return types"; {(fst $5) with out = Some $3}, fun c -> (snd $5) c } | LPAR LOCAL value_type_list RPAR func_fields @@ -437,7 +443,7 @@ module_fields : | memory module_fields { fun c -> let m = $2 c in match m.memory with - | Some _ -> Error.error $1.at "more than one memory section" + | Some _ -> error $1.at "multiple memory sections" | None -> {m with memory = Some $1} } ; module_ : diff --git a/ml-proto/host/script.ml b/ml-proto/host/script.ml index 233a0109cf..4a8b80f204 100644 --- a/ml-proto/host/script.ml +++ b/ml-proto/host/script.ml @@ -21,35 +21,20 @@ type script = command list (* Execution *) +module Syntax = Error.Make () +module AssertFailure = Error.Make () + +exception Syntax = Syntax.Error +exception AssertFailure = AssertFailure.Error (* assert command failure *) + let trace name = if !Flags.trace then print_endline ("-- " ^ name) let current_module : Eval.instance option ref = ref None let get_module at = match !current_module with | Some m -> m - | None -> Error.error at "no module defined to invoke" - -let show_value label v = begin - print_string (label ^ ": "); - Print.print_value v -end - -let show_result got_v = begin - show_value "Result" got_v -end - -let show_result_expect got_v expect_v = begin - show_result got_v; - show_value "Expect" expect_v -end - -let assert_error f err re at = - match f () with - | exception Error.Error (_, s) -> - if not (Str.string_match (Str.regexp re) s 0) then - Error.error at ("failure \"" ^ s ^ "\" does not match: \"" ^ re ^ "\"") - | _ -> - Error.error at ("expected " ^ err) + | None -> raise (Eval.Crash (at, "no module defined to invoke")) + let run_command cmd = match cmd.it with @@ -76,73 +61,56 @@ let run_command cmd = | AssertInvalid (m, re) -> trace "Asserting invalid..."; - assert_error (fun () -> Check.check_module m) "invalid module" re cmd.at + (match Check.check_module m with + | exception Check.Invalid (_, msg) -> + if not (Str.string_match (Str.regexp re) msg 0) then begin + print_endline ("Result: \"" ^ msg ^ "\""); + print_endline ("Expect: \"" ^ re ^ "\""); + AssertFailure.error cmd.at "wrong validation error" + end + | _ -> + AssertFailure.error cmd.at "expected validation error" + ) | AssertReturn (name, es, expect_e) -> - let open Values in trace "Asserting return..."; let m = get_module cmd.at in let got_v = Eval.invoke m name (List.map it es) in let expect_v = Lib.Option.map it expect_e in - (match got_v, expect_v with - | None, None -> () - | Some (Int32 got_i32), Some (Int32 expect_i32) -> - if got_i32 <> expect_i32 then begin - show_result_expect got_v expect_v; - Error.error cmd.at "assert_return i32 operands are not equal" - end - | Some (Int64 got_i64), Some (Int64 expect_i64) -> - if got_i64 <> expect_i64 then begin - show_result_expect got_v expect_v; - Error.error cmd.at "assert_return i64 operands are not equal" - end - | Some (Float32 got_f32), Some (Float32 expect_f32) -> - if (F32.to_bits got_f32) <> (F32.to_bits expect_f32) then begin - show_result_expect got_v expect_v; - Error.error cmd.at - "assert_return f32 operands have different bit patterns" - end - | Some (Float64 got_f64), Some (Float64 expect_f64) -> - if (F64.to_bits got_f64) <> (F64.to_bits expect_f64) then begin - show_result_expect got_v expect_v; - Error.error cmd.at - "assert_return f64 operands have different bit patterns" - end - | _, _ -> - begin - show_result_expect got_v expect_v; - Error.error cmd.at "assert_return operands must be the same type" - end - ) + if got_v <> expect_v then begin + print_string "Result: "; Print.print_value got_v; + print_string "Expect: "; Print.print_value expect_v; + AssertFailure.error cmd.at "wrong return value" + end | AssertReturnNaN (name, es) -> - let open Values in trace "Asserting return..."; let m = get_module cmd.at in let got_v = Eval.invoke m name (List.map it es) in - (match got_v with - | Some (Float32 got_f32) -> - if (F32.eq got_f32 got_f32) then begin - show_result got_v; - Error.error cmd.at "assert_return_nan f32 operand is not a NaN" - end - | Some (Float64 got_f64) -> - if (F64.eq got_f64 got_f64) then begin - show_result got_v; - Error.error cmd.at "assert_return_nan f64 operand is not a NaN" - end - | _ -> - begin - show_result got_v; - Error.error cmd.at "assert_return_nan operand must be f32 or f64" - end - ) + if + match got_v with + | Some (Values.Float32 got_f32) -> F32.eq got_f32 got_f32 + | Some (Values.Float64 got_f64) -> F64.eq got_f64 got_f64 + | _ -> true + then begin + print_string "Result: "; Print.print_value got_v; + print_string "Expect: "; print_endline "nan"; + AssertFailure.error cmd.at "wrong return value" + end | AssertTrap (name, es, re) -> trace "Asserting trap..."; let m = get_module cmd.at in - assert_error (fun () -> Eval.invoke m name (List.map it es)) - "trap" re cmd.at + (match Eval.invoke m name (List.map it es) with + | exception Eval.Trap (_, msg) -> + if not (Str.string_match (Str.regexp re) msg 0) then begin + print_endline ("Result: \"" ^ msg ^ "\""); + print_endline ("Expect: \"" ^ re ^ "\""); + AssertFailure.error cmd.at "wrong runtime trap" + end + | _ -> + AssertFailure.error cmd.at "expected runtime trap" + ) let dry_command cmd = match cmd.it with diff --git a/ml-proto/host/script.mli b/ml-proto/host/script.mli index 25f45ddc01..4214ae2eb1 100644 --- a/ml-proto/host/script.mli +++ b/ml-proto/host/script.mli @@ -13,5 +13,10 @@ and command' = type script = command list -val run : script -> unit (* raises Error.Error *) +exception Syntax of Source.region * string +exception AssertFailure of Source.region * string + +val run : script -> unit + (* raises Check.Invalid, Eval.Trap, Eval.Crash, Failure *) + val trace : string -> unit diff --git a/ml-proto/spec/check.ml b/ml-proto/spec/check.ml index 019c11d1de..113ceb1ef9 100644 --- a/ml-proto/spec/check.ml +++ b/ml-proto/spec/check.ml @@ -9,7 +9,10 @@ open Types (* Errors *) -let error = Error.error +module Invalid = Error.Make () +exception Invalid = Invalid.Error + +let error = Invalid.error let require b at s = if not b then error at s diff --git a/ml-proto/spec/check.mli b/ml-proto/spec/check.mli index 09e2a24cb0..fc780d6b8d 100644 --- a/ml-proto/spec/check.mli +++ b/ml-proto/spec/check.mli @@ -2,4 +2,6 @@ * (c) 2015 Andreas Rossberg *) -val check_module : Ast.module_ -> unit (* raise Error *) +exception Invalid of Source.region * string + +val check_module : Ast.module_ -> unit (* raise Invalid *) diff --git a/ml-proto/spec/error.ml b/ml-proto/spec/error.ml index bc5bd93b14..926428a183 100644 --- a/ml-proto/spec/error.ml +++ b/ml-proto/spec/error.ml @@ -2,7 +2,11 @@ * (c) 2015 Andreas Rossberg *) -exception Error of Source.region * string +module Make () = +struct + exception Error of Source.region * string + + let warn at m = prerr_endline (Source.string_of_region at ^ ": warning: " ^ m) + let error at m = raise (Error (at, m)) +end -let warn at m = prerr_endline (Source.string_of_region at ^ ": warning: " ^ m) -let error at m = raise (Error (at, m)) diff --git a/ml-proto/spec/error.mli b/ml-proto/spec/error.mli index ffeba4223b..d9fcb82946 100644 --- a/ml-proto/spec/error.mli +++ b/ml-proto/spec/error.mli @@ -2,7 +2,11 @@ * (c) 2015 Andreas Rossberg *) -exception Error of Source.region * string +module Make () : +sig + exception Error of Source.region * string + + val warn : Source.region -> string -> unit + val error : Source.region -> string -> 'a (* raises Error *) +end -val warn : Source.region -> string -> unit -val error : Source.region -> string -> 'a (* raises Error *) diff --git a/ml-proto/spec/eval.ml b/ml-proto/spec/eval.ml index 72a6cdd7bc..7574c01710 100644 --- a/ml-proto/spec/eval.ml +++ b/ml-proto/spec/eval.ml @@ -7,8 +7,6 @@ open Types open Ast open Source -let error = Error.error - (* Module Instances *) @@ -32,6 +30,38 @@ type instance = } +(* Errors *) + +module Trap = Error.Make () +module Crash = Error.Make () + +exception Trap = Trap.Error +exception Crash = Crash.Error + (* A crash is an execution failure that cannot legally happen in checked + * code; it indicates an internal inconsistency in the spec. *) + +let memory_error at = function + | Memory.Bounds -> Trap.error at "out of bounds memory access" + | Memory.SizeOverflow -> Trap.error at "memory size overflow" + | exn -> raise exn + +let type_error at v t = + Crash.error at + ("type error, expected " ^ Types.string_of_value_type t ^ + ", got " ^ Types.string_of_value_type (type_of v)) + +let arithmetic_error at at_op1 at_op2 = function + | Arithmetic.TypeError (i, v, t) -> + type_error (if i = 1 then at_op1 else at_op2) v t + | Numerics.IntegerOverflow -> + Trap.error at "integer overflow" + | Numerics.IntegerDivideByZero -> + Trap.error at "integer divide by zero" + | Numerics.InvalidConversionToInteger -> + Trap.error at "invalid conversion to integer" + | exn -> raise exn + + (* Configurations *) type label = value option -> exn @@ -45,7 +75,7 @@ type config = let lookup category list x = try List.nth list x.it with Failure _ -> - error x.at ("runtime: undefined " ^ category ^ " " ^ string_of_int x.it) + Crash.error x.at ("undefined " ^ category ^ " " ^ string_of_int x.it) let type_ c x = lookup "type" c.instance.module_.it.types x let func c x = lookup "function" c.instance.module_.it.funcs x @@ -53,16 +83,17 @@ let import c x = lookup "import" c.instance.imports x let local c x = lookup "local" c.locals x let label c x = lookup "label" c.labels x -let table_elem c i at = - if i < 0l || i <> Int32.of_int (Int32.to_int i) then - error at ("runtime: undefined table element " ^ Int32.to_string i); - let x = (Int32.to_int i) @@ at in - lookup "table element" c.instance.module_.it.table x +let export m name = + try ExportMap.find name.it m.exports with Not_found -> + Crash.error name.at ("undefined export \"" ^ name.it ^ "\"") -let export m x = - try ExportMap.find x.it m.exports - with Not_found -> - error x.at ("runtime: undefined export " ^ x.it) +let table_elem c i at = + try + let j = Int32.to_int i in + if i < 0l || i <> Int32.of_int j then raise (Failure ""); + List.nth c.instance.module_.it.table j + with Failure _ -> + Trap.error at ("undefined table index " ^ Int32.to_string i) module MakeLabel () = struct @@ -71,56 +102,25 @@ struct end -(* Type and memory errors *) - -let memory_error at = function - | Memory.Bounds -> error at "runtime: out of bounds memory access" - | Memory.SizeOverflow -> error at "runtime: memory size overflow" - | exn -> raise exn - -let type_error at v t = - error at - ("runtime: type error, expected " ^ string_of_value_type t ^ - ", got " ^ string_of_value_type (type_of v)) - -let numerics_error at = function - | Numerics.IntegerOverflow -> - error at "runtime: integer overflow" - | Numerics.IntegerDivideByZero -> - error at "runtime: integer divide by zero" - | Numerics.InvalidConversionToInteger -> - error at "runtime: invalid conversion to integer" - | exn -> raise exn - -let some_memory c at = - match c.instance.memory with - | Some m -> m - | _ -> error at "memory operation but no memory section" +(* Type conversions *) let some v at = match v with | Some v -> v - | None -> error at "runtime: expression produced no value" + | None -> Crash.error at "type error, expression produced no value" let int32 v at = match some v at with | Int32 i -> i | v -> type_error at v Int32Type -let mem_size v at = - let i32 = int32 v at in - let i64 = Int64.of_int32 i32 in - Int64.shift_right_logical (Int64.shift_left i64 32) 32 +let address32 v at = + Int64.logand (Int64.of_int32 (int32 v at)) 0xffffffffL -(* - * Test whether x has a value which is an overflow in the memory type. Since - * we currently only support i32, just test that. - *) -let mem_overflow x = - I64.gt_u x (Int64.of_int32 Int32.max_int) - -let callstack_exhaustion at = - error at ("runtime: callstack exhausted") +let memory c at = + match c.instance.memory with + | Some m -> m + | _ -> Trap.error at "memory operation with no memory" (* Evaluation *) @@ -180,7 +180,7 @@ let rec eval_expr (c : config) (e : expr) = let vs = List.map (fun vo -> some (eval_expr c vo) vo.at) es in let f = func c (table_elem c i e1.at) in if ftype.it <> f.it.ftype.it then - error e1.at "runtime: indirect call signature mismatch"; + Trap.error e1.at "indirect call signature mismatch"; eval_func c.instance f vs | GetLocal x -> @@ -192,28 +192,28 @@ let rec eval_expr (c : config) (e : expr) = Some v1 | Load ({ty; offset; align = _}, e1) -> - let mem = some_memory c e.at in - let v1 = mem_size (eval_expr c e1) e1.at in + let mem = memory c e.at in + let v1 = address32 (eval_expr c e1) e1.at in (try Some (Memory.load mem v1 offset ty) with exn -> memory_error e.at exn) | Store ({ty = _; offset; align = _}, e1, e2) -> - let mem = some_memory c e.at in - let v1 = mem_size (eval_expr c e1) e1.at in + let mem = memory c e.at in + let v1 = address32 (eval_expr c e1) e1.at in let v2 = some (eval_expr c e2) e2.at in (try Memory.store mem v1 offset v2 with exn -> memory_error e.at exn); Some v2 | LoadExtend ({memop = {ty; offset; align = _}; sz; ext}, e1) -> - let mem = some_memory c e.at in - let v1 = mem_size (eval_expr c e1) e1.at in + let mem = memory c e.at in + let v1 = address32 (eval_expr c e1) e1.at in (try Some (Memory.load_extend mem v1 offset sz ext ty) with exn -> memory_error e.at exn) | StoreWrap ({memop = {ty; offset; align = _}; sz}, e1, e2) -> - let mem = some_memory c e.at in - let v1 = mem_size (eval_expr c e1) e1.at in + let mem = memory c e.at in + let v1 = address32 (eval_expr c e1) e1.at in let v2 = some (eval_expr c e2) e2.at in (try Memory.store_wrap mem v1 offset sz v2 with exn -> memory_error e.at exn); @@ -225,39 +225,28 @@ let rec eval_expr (c : config) (e : expr) = | Unary (unop, e1) -> let v1 = some (eval_expr c e1) e1.at in (try Some (Arithmetic.eval_unop unop v1) - with - | Arithmetic.TypeError (_, v, t) -> type_error e1.at v t - | exn -> numerics_error e.at exn) + with exn -> arithmetic_error e.at e1.at e1.at exn) | Binary (binop, e1, e2) -> let v1 = some (eval_expr c e1) e1.at in let v2 = some (eval_expr c e2) e2.at in (try Some (Arithmetic.eval_binop binop v1 v2) - with - | Arithmetic.TypeError (i, v, t) -> - type_error (if i = 1 then e1 else e2).at v t - | exn -> numerics_error e.at exn) + with exn -> arithmetic_error e.at e1.at e2.at exn) | Compare (relop, e1, e2) -> let v1 = some (eval_expr c e1) e1.at in let v2 = some (eval_expr c e2) e2.at in - (try - let b = Arithmetic.eval_relop relop v1 v2 in - Some (Int32 Int32.(if b then one else zero)) - with Arithmetic.TypeError (i, v, t) -> - type_error (if i = 1 then e1 else e2).at v t) + (try Some (Int32 (if Arithmetic.eval_relop relop v1 v2 then 1l else 0l)) + with exn -> arithmetic_error e.at e1.at e2.at exn) | Convert (cvt, e1) -> let v1 = some (eval_expr c e1) e1.at in (try Some (Arithmetic.eval_cvt cvt v1) - with - | Arithmetic.TypeError (_, v, t) -> type_error e1.at v t - | exn -> numerics_error e.at exn) + with exn -> arithmetic_error e.at e1.at e1.at exn) | Host (hostop, es) -> let vs = List.map (eval_expr c) es in - let mem_opt = c.instance.memory in - eval_hostop c.instance.host mem_opt hostop vs e.at + eval_hostop c hostop vs e.at and eval_expr_opt c = function | Some e -> eval_expr c e @@ -286,34 +275,38 @@ and coerce et vo = (* Host operators *) -and eval_hostop host mem_opt hostop vs at = +and eval_hostop c hostop vs at = + let host = c.instance.host in match hostop, vs with | PageSize, [] -> assert (I64.lt_u host.page_size (Int64.of_int32 Int32.max_int)); Some (Int32 (Int64.to_int32 host.page_size)) | MemorySize, [] -> - let mem = some mem_opt at in + let mem = memory c at in assert (I64.lt_u (Memory.size mem) (Int64.of_int32 Int32.max_int)); Some (Int32 (Int64.to_int32 (Memory.size mem))) | GrowMemory, [v] -> - let mem = some mem_opt at in - let delta = mem_size v at in + let mem = memory c at in + let delta = address32 v at in if I64.rem_u delta host.page_size <> 0L then - error at "runtime: grow_memory operand not multiple of page_size"; - if I64.lt_u (Int64.add (Memory.size mem) delta) (Memory.size mem) then - error at "runtime: grow_memory overflow"; - if mem_overflow (Int64.add (Memory.size mem) delta) then - error at "runtime: grow_memory overflow"; + Trap.error at "growing memory by non-multiple of page size"; + let new_size = Int64.add (Memory.size mem) delta in + if I64.lt_u new_size (Memory.size mem) then + Trap.error at "memory size overflow"; + (* Test whether the new size overflows the memory type. + * Since we currently only support i32, just test that. *) + if I64.gt_u new_size (Int64.of_int32 Int32.max_int) then + Trap.error at "memory size exceeds implementation limit"; Memory.grow mem delta; - None; + None | HasFeature str, [] -> Some (Int32 (if host.has_feature str then 1l else 0l)) | _, _ -> - error at "runtime: invalid invocation of host operator" + Crash.error at "invalid invocation of host operator" (* Modules *) @@ -340,4 +333,4 @@ let init m imports host = let invoke instance name vs = try eval_func instance (export instance (name @@ no_region)) vs - with Stack_overflow -> callstack_exhaustion no_region + with Stack_overflow -> Trap.error Source.no_region "call stack exhausted" diff --git a/ml-proto/spec/eval.mli b/ml-proto/spec/eval.mli index 43cad9b1d3..5ea292f0e6 100644 --- a/ml-proto/spec/eval.mli +++ b/ml-proto/spec/eval.mli @@ -10,7 +10,10 @@ type host_params = { has_feature : string -> bool } +exception Trap of Source.region * string +exception Crash of Source.region * string + val init : Ast.module_ -> import list -> host_params -> instance val invoke : instance -> string -> value list -> value option - (* raise Error.Error *) + (* raises Trap, Crash *) diff --git a/ml-proto/spec/float.ml b/ml-proto/spec/float.ml index 99f2af704b..1e326fdcb0 100644 --- a/ml-proto/spec/float.ml +++ b/ml-proto/spec/float.ml @@ -50,7 +50,7 @@ sig val le : t -> t -> bool val gt : t -> t -> bool val ge : t -> t -> bool - val zero: t + val zero : t end module Make(Rep : RepresentationType) : S with type bits = Rep.t = diff --git a/ml-proto/spec/memory.mli b/ml-proto/spec/memory.mli index 3f3a1cc7d5..d7595cebdf 100644 --- a/ml-proto/spec/memory.mli +++ b/ml-proto/spec/memory.mli @@ -5,8 +5,8 @@ type memory type t = memory type address = int64 -type size = address -type offset = address +type size = int64 +type offset = int64 type mem_size = Mem8 | Mem16 | Mem32 type extension = SX | ZX type segment = {addr : address; data : string} @@ -21,8 +21,10 @@ val create : size -> memory val init : memory -> segment list -> unit val size : memory -> size val grow : memory -> size -> unit + val load : memory -> address -> offset -> value_type -> value val store : memory -> address -> offset -> value -> unit val load_extend : memory -> address -> offset -> mem_size -> extension -> value_type -> value val store_wrap : memory -> address -> offset -> mem_size -> value -> unit + diff --git a/ml-proto/test/address.wast b/ml-proto/test/address.wast index 9a16ffd70e..d147debda5 100644 --- a/ml-proto/test/address.wast +++ b/ml-proto/test/address.wast @@ -28,8 +28,8 @@ (assert_return (invoke "good" (i32.const 0))) (assert_return (invoke "good" (i32.const 995))) -(assert_trap (invoke "good" (i32.const 996)) "runtime: out of bounds memory access") -(assert_trap (invoke "bad1" (i32.const 0)) "runtime: out of bounds memory access") -(assert_trap (invoke "bad1" (i32.const 1)) "runtime: out of bounds memory access") -(assert_trap (invoke "bad2" (i32.const 0)) "runtime: out of bounds memory access") -(assert_trap (invoke "bad2" (i32.const 1)) "runtime: out of bounds memory access") +(assert_trap (invoke "good" (i32.const 996)) "out of bounds memory access") +(assert_trap (invoke "bad1" (i32.const 0)) "out of bounds memory access") +(assert_trap (invoke "bad1" (i32.const 1)) "out of bounds memory access") +(assert_trap (invoke "bad2" (i32.const 0)) "out of bounds memory access") +(assert_trap (invoke "bad2" (i32.const 1)) "out of bounds memory access") diff --git a/ml-proto/test/conversions.wast b/ml-proto/test/conversions.wast index 57538c8b3f..2505ab5e0d 100644 --- a/ml-proto/test/conversions.wast +++ b/ml-proto/test/conversions.wast @@ -116,11 +116,11 @@ (assert_return (invoke "i32.trunc_s_f32" (f32.const -2.0)) (i32.const -2)) (assert_return (invoke "i32.trunc_s_f32" (f32.const 2147483520.0)) (i32.const 2147483520)) (assert_return (invoke "i32.trunc_s_f32" (f32.const -2147483648.0)) (i32.const -2147483648)) -(assert_trap (invoke "i32.trunc_s_f32" (f32.const 2147483648.0)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_s_f32" (f32.const -2147483904.0)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_s_f32" (f32.const infinity)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_s_f32" (f32.const -infinity)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_s_f32" (f32.const nan)) "runtime: invalid conversion to integer") +(assert_trap (invoke "i32.trunc_s_f32" (f32.const 2147483648.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f32" (f32.const -2147483904.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f32" (f32.const infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f32" (f32.const -infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f32" (f32.const nan)) "invalid conversion to integer") (assert_return (invoke "i32.trunc_u_f32" (f32.const 0.0)) (i32.const 0)) (assert_return (invoke "i32.trunc_u_f32" (f32.const -0.0)) (i32.const 0)) @@ -134,11 +134,11 @@ (assert_return (invoke "i32.trunc_u_f32" (f32.const 2147483648)) (i32.const -2147483648)) ;; 0x1.00000p+31 -> 8000 0000 (assert_return (invoke "i32.trunc_u_f32" (f32.const 4294967040.0)) (i32.const -256)) (assert_return (invoke "i32.trunc_u_f32" (f32.const -0.9)) (i32.const 0)) -(assert_trap (invoke "i32.trunc_u_f32" (f32.const 4294967296.0)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_u_f32" (f32.const -1.0)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_u_f32" (f32.const infinity)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_u_f32" (f32.const -infinity)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_u_f32" (f32.const nan)) "runtime: invalid conversion to integer") +(assert_trap (invoke "i32.trunc_u_f32" (f32.const 4294967296.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f32" (f32.const -1.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f32" (f32.const infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f32" (f32.const -infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f32" (f32.const nan)) "invalid conversion to integer") (assert_return (invoke "i32.trunc_s_f64" (f64.const 0.0)) (i32.const 0)) (assert_return (invoke "i32.trunc_s_f64" (f64.const -0.0)) (i32.const 0)) @@ -154,11 +154,11 @@ (assert_return (invoke "i32.trunc_s_f64" (f64.const -2.0)) (i32.const -2)) (assert_return (invoke "i32.trunc_s_f64" (f64.const 2147483647.0)) (i32.const 2147483647)) (assert_return (invoke "i32.trunc_s_f64" (f64.const -2147483648.0)) (i32.const -2147483648)) -(assert_trap (invoke "i32.trunc_s_f64" (f64.const 2147483648.0)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_s_f64" (f64.const -2147483649.0)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_s_f64" (f64.const infinity)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_s_f64" (f64.const -infinity)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_s_f64" (f64.const nan)) "runtime: invalid conversion to integer") +(assert_trap (invoke "i32.trunc_s_f64" (f64.const 2147483648.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f64" (f64.const -2147483649.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f64" (f64.const infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f64" (f64.const -infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_s_f64" (f64.const nan)) "invalid conversion to integer") (assert_return (invoke "i32.trunc_u_f64" (f64.const 0.0)) (i32.const 0)) (assert_return (invoke "i32.trunc_u_f64" (f64.const -0.0)) (i32.const 0)) @@ -173,14 +173,14 @@ (assert_return (invoke "i32.trunc_u_f64" (f64.const 4294967295.0)) (i32.const -1)) (assert_return (invoke "i32.trunc_u_f64" (f64.const -0.9)) (i32.const 0)) (assert_return (invoke "i32.trunc_u_f64" (f64.const 1e8)) (i32.const 100000000)) -(assert_trap (invoke "i32.trunc_u_f64" (f64.const 4294967296.0)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_u_f64" (f64.const -1.0)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_u_f64" (f64.const 1e16)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_u_f64" (f64.const 1e30)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_u_f64" (f64.const 9223372036854775808)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_u_f64" (f64.const infinity)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_u_f64" (f64.const -infinity)) "runtime: integer overflow") -(assert_trap (invoke "i32.trunc_u_f64" (f64.const nan)) "runtime: invalid conversion to integer") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const 4294967296.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const -1.0)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const 1e16)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const 1e30)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const 9223372036854775808)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const -infinity)) "integer overflow") +(assert_trap (invoke "i32.trunc_u_f64" (f64.const nan)) "invalid conversion to integer") (assert_return (invoke "i64.trunc_s_f32" (f32.const 0.0)) (i64.const 0)) (assert_return (invoke "i64.trunc_s_f32" (f32.const -0.0)) (i64.const 0)) @@ -198,11 +198,11 @@ (assert_return (invoke "i64.trunc_s_f32" (f32.const -4294967296)) (i64.const -4294967296)) ;; -0x1.00000p+32 -> ffff ffff 0000 0000 (assert_return (invoke "i64.trunc_s_f32" (f32.const 9223371487098961920.0)) (i64.const 9223371487098961920)) (assert_return (invoke "i64.trunc_s_f32" (f32.const -9223372036854775808.0)) (i64.const -9223372036854775808)) -(assert_trap (invoke "i64.trunc_s_f32" (f32.const 9223372036854775808.0)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_s_f32" (f32.const -9223373136366403584.0)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_s_f32" (f32.const infinity)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_s_f32" (f32.const -infinity)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_s_f32" (f32.const nan)) "runtime: invalid conversion to integer") +(assert_trap (invoke "i64.trunc_s_f32" (f32.const 9223372036854775808.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f32" (f32.const -9223373136366403584.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f32" (f32.const infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f32" (f32.const -infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f32" (f32.const nan)) "invalid conversion to integer") (assert_return (invoke "i64.trunc_u_f32" (f32.const 0.0)) (i64.const 0)) (assert_return (invoke "i64.trunc_u_f32" (f32.const -0.0)) (i64.const 0)) @@ -214,11 +214,11 @@ (assert_return (invoke "i64.trunc_u_f32" (f32.const 4294967296)) (i64.const 4294967296)) (assert_return (invoke "i64.trunc_u_f32" (f32.const 18446742974197923840.0)) (i64.const -1099511627776)) (assert_return (invoke "i64.trunc_u_f32" (f32.const -0.9)) (i64.const 0)) -(assert_trap (invoke "i64.trunc_u_f32" (f32.const 18446744073709551616.0)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_u_f32" (f32.const -1.0)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_u_f32" (f32.const infinity)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_u_f32" (f32.const -infinity)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_u_f32" (f32.const nan)) "runtime: invalid conversion to integer") +(assert_trap (invoke "i64.trunc_u_f32" (f32.const 18446744073709551616.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f32" (f32.const -1.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f32" (f32.const infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f32" (f32.const -infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f32" (f32.const nan)) "invalid conversion to integer") (assert_return (invoke "i64.trunc_s_f64" (f64.const 0.0)) (i64.const 0)) (assert_return (invoke "i64.trunc_s_f64" (f64.const -0.0)) (i64.const 0)) @@ -236,11 +236,11 @@ (assert_return (invoke "i64.trunc_s_f64" (f64.const -4294967296)) (i64.const -4294967296)) ;; -0x1.00000p+32 -> ffff ffff 0000 0000 (assert_return (invoke "i64.trunc_s_f64" (f64.const 9223372036854774784.0)) (i64.const 9223372036854774784)) (assert_return (invoke "i64.trunc_s_f64" (f64.const -9223372036854775808.0)) (i64.const -9223372036854775808)) -(assert_trap (invoke "i64.trunc_s_f64" (f64.const 9223372036854775808.0)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_s_f64" (f64.const -9223372036854777856.0)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_s_f64" (f64.const infinity)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_s_f64" (f64.const -infinity)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_s_f64" (f64.const nan)) "runtime: invalid conversion to integer") +(assert_trap (invoke "i64.trunc_s_f64" (f64.const 9223372036854775808.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f64" (f64.const -9223372036854777856.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f64" (f64.const infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f64" (f64.const -infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_s_f64" (f64.const nan)) "invalid conversion to integer") (assert_return (invoke "i64.trunc_u_f64" (f64.const 0.0)) (i64.const 0)) (assert_return (invoke "i64.trunc_u_f64" (f64.const -0.0)) (i64.const 0)) @@ -256,11 +256,11 @@ (assert_return (invoke "i64.trunc_u_f64" (f64.const 1e8)) (i64.const 100000000)) (assert_return (invoke "i64.trunc_u_f64" (f64.const 1e16)) (i64.const 10000000000000000)) (assert_return (invoke "i64.trunc_u_f64" (f64.const 9223372036854775808)) (i64.const -9223372036854775808)) -(assert_trap (invoke "i64.trunc_u_f64" (f64.const 18446744073709551616.0)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_u_f64" (f64.const -1.0)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_u_f64" (f64.const infinity)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_u_f64" (f64.const -infinity)) "runtime: integer overflow") -(assert_trap (invoke "i64.trunc_u_f64" (f64.const nan)) "runtime: invalid conversion to integer") +(assert_trap (invoke "i64.trunc_u_f64" (f64.const 18446744073709551616.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f64" (f64.const -1.0)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f64" (f64.const infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f64" (f64.const -infinity)) "integer overflow") +(assert_trap (invoke "i64.trunc_u_f64" (f64.const nan)) "invalid conversion to integer") (assert_return (invoke "f32.convert_s_i32" (i32.const 1)) (f32.const 1.0)) (assert_return (invoke "f32.convert_s_i32" (i32.const -1)) (f32.const -1.0)) diff --git a/ml-proto/test/fac.wast b/ml-proto/test/fac.wast index cca812f94a..8808c97f79 100644 --- a/ml-proto/test/fac.wast +++ b/ml-proto/test/fac.wast @@ -71,4 +71,4 @@ (assert_return (invoke "fac-iter" (i64.const 25)) (i64.const 7034535277573963776)) (assert_return (invoke "fac-rec-named" (i64.const 25)) (i64.const 7034535277573963776)) (assert_return (invoke "fac-iter-named" (i64.const 25)) (i64.const 7034535277573963776)) -(assert_trap (invoke "fac-rec" (i64.const 1073741824)) "runtime: callstack exhausted") +(assert_trap (invoke "fac-rec" (i64.const 1073741824)) "call stack exhausted") diff --git a/ml-proto/test/func_ptrs.wast b/ml-proto/test/func_ptrs.wast index 43d65bd289..734ac59e86 100644 --- a/ml-proto/test/func_ptrs.wast +++ b/ml-proto/test/func_ptrs.wast @@ -58,20 +58,20 @@ (assert_return (invoke "callt" (i32.const 0)) (i32.const 1)) (assert_return (invoke "callt" (i32.const 1)) (i32.const 2)) (assert_return (invoke "callt" (i32.const 2)) (i32.const 3)) -(assert_trap (invoke "callt" (i32.const 3)) "runtime: indirect call signature mismatch") -(assert_trap (invoke "callt" (i32.const 4)) "runtime: indirect call signature mismatch") +(assert_trap (invoke "callt" (i32.const 3)) "indirect call signature mismatch") +(assert_trap (invoke "callt" (i32.const 4)) "indirect call signature mismatch") (assert_return (invoke "callt" (i32.const 5)) (i32.const 1)) (assert_return (invoke "callt" (i32.const 6)) (i32.const 3)) -(assert_trap (invoke "callt" (i32.const 7)) "runtime: undefined table element 7") -(assert_trap (invoke "callt" (i32.const 100)) "runtime: undefined table element 100") -(assert_trap (invoke "callt" (i32.const -1)) "runtime: undefined table element -1") +(assert_trap (invoke "callt" (i32.const 7)) "undefined table index 7") +(assert_trap (invoke "callt" (i32.const 100)) "undefined table index 100") +(assert_trap (invoke "callt" (i32.const -1)) "undefined table index -1") -(assert_trap (invoke "callu" (i32.const 0)) "runtime: indirect call signature mismatch") -(assert_trap (invoke "callu" (i32.const 1)) "runtime: indirect call signature mismatch") -(assert_trap (invoke "callu" (i32.const 2)) "runtime: indirect call signature mismatch") +(assert_trap (invoke "callu" (i32.const 0)) "indirect call signature mismatch") +(assert_trap (invoke "callu" (i32.const 1)) "indirect call signature mismatch") +(assert_trap (invoke "callu" (i32.const 2)) "indirect call signature mismatch") (assert_return (invoke "callu" (i32.const 3)) (i32.const 4)) (assert_return (invoke "callu" (i32.const 4)) (i32.const 5)) -(assert_trap (invoke "callu" (i32.const 5)) "runtime: indirect call signature mismatch") -(assert_trap (invoke "callu" (i32.const 6)) "runtime: indirect call signature mismatch") -(assert_trap (invoke "callu" (i32.const 7)) "runtime: undefined table element 7") -(assert_trap (invoke "callu" (i32.const -1)) "runtime: undefined table element -1") +(assert_trap (invoke "callu" (i32.const 5)) "indirect call signature mismatch") +(assert_trap (invoke "callu" (i32.const 6)) "indirect call signature mismatch") +(assert_trap (invoke "callu" (i32.const 7)) "undefined table index 7") +(assert_trap (invoke "callu" (i32.const -1)) "undefined table index -1") diff --git a/ml-proto/test/i32.wast b/ml-proto/test/i32.wast index bec28a8f84..3cc1d1756d 100644 --- a/ml-proto/test/i32.wast +++ b/ml-proto/test/i32.wast @@ -82,9 +82,9 @@ (assert_return (invoke "mul" (i32.const 0x7fffffff) (i32.const -1)) (i32.const 0x80000001)) (assert_return (invoke "mul" (i32.const 0x01234567) (i32.const 0x76543210)) (i32.const 0x358e7470)) -(assert_trap (invoke "div_s" (i32.const 1) (i32.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "div_s" (i32.const 0) (i32.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "div_s" (i32.const 0x80000000) (i32.const -1)) "runtime: integer overflow") +(assert_trap (invoke "div_s" (i32.const 1) (i32.const 0)) "integer divide by zero") +(assert_trap (invoke "div_s" (i32.const 0) (i32.const 0)) "integer divide by zero") +(assert_trap (invoke "div_s" (i32.const 0x80000000) (i32.const -1)) "integer overflow") (assert_return (invoke "div_s" (i32.const 1) (i32.const 1)) (i32.const 1)) (assert_return (invoke "div_s" (i32.const 0) (i32.const 1)) (i32.const 0)) (assert_return (invoke "div_s" (i32.const -1) (i32.const -1)) (i32.const 1)) @@ -101,8 +101,8 @@ (assert_return (invoke "div_s" (i32.const 11) (i32.const 5)) (i32.const 2)) (assert_return (invoke "div_s" (i32.const 17) (i32.const 7)) (i32.const 2)) -(assert_trap (invoke "div_u" (i32.const 1) (i32.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "div_u" (i32.const 0) (i32.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "div_u" (i32.const 1) (i32.const 0)) "integer divide by zero") +(assert_trap (invoke "div_u" (i32.const 0) (i32.const 0)) "integer divide by zero") (assert_return (invoke "div_u" (i32.const 1) (i32.const 1)) (i32.const 1)) (assert_return (invoke "div_u" (i32.const 0) (i32.const 1)) (i32.const 0)) (assert_return (invoke "div_u" (i32.const -1) (i32.const -1)) (i32.const 1)) @@ -118,8 +118,8 @@ (assert_return (invoke "div_u" (i32.const 11) (i32.const 5)) (i32.const 2)) (assert_return (invoke "div_u" (i32.const 17) (i32.const 7)) (i32.const 2)) -(assert_trap (invoke "rem_s" (i32.const 1) (i32.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "rem_s" (i32.const 0) (i32.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "rem_s" (i32.const 1) (i32.const 0)) "integer divide by zero") +(assert_trap (invoke "rem_s" (i32.const 0) (i32.const 0)) "integer divide by zero") (assert_return (invoke "rem_s" (i32.const 0x7fffffff) (i32.const -1)) (i32.const 0)) (assert_return (invoke "rem_s" (i32.const 1) (i32.const 1)) (i32.const 0)) (assert_return (invoke "rem_s" (i32.const 0) (i32.const 1)) (i32.const 0)) @@ -138,8 +138,8 @@ (assert_return (invoke "rem_s" (i32.const 11) (i32.const 5)) (i32.const 1)) (assert_return (invoke "rem_s" (i32.const 17) (i32.const 7)) (i32.const 3)) -(assert_trap (invoke "rem_u" (i32.const 1) (i32.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "rem_u" (i32.const 0) (i32.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "rem_u" (i32.const 1) (i32.const 0)) "integer divide by zero") +(assert_trap (invoke "rem_u" (i32.const 0) (i32.const 0)) "integer divide by zero") (assert_return (invoke "rem_u" (i32.const 1) (i32.const 1)) (i32.const 0)) (assert_return (invoke "rem_u" (i32.const 0) (i32.const 1)) (i32.const 0)) (assert_return (invoke "rem_u" (i32.const -1) (i32.const -1)) (i32.const 0)) diff --git a/ml-proto/test/i64.wast b/ml-proto/test/i64.wast index 6f11a7f36e..41a7f96271 100644 --- a/ml-proto/test/i64.wast +++ b/ml-proto/test/i64.wast @@ -82,9 +82,9 @@ (assert_return (invoke "mul" (i64.const 0x7fffffffffffffff) (i64.const -1)) (i64.const 0x8000000000000001)) (assert_return (invoke "mul" (i64.const 0x0123456789abcdef) (i64.const 0xfedcba9876543210)) (i64.const 0x2236d88fe5618cf0)) -(assert_trap (invoke "div_s" (i64.const 1) (i64.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "div_s" (i64.const 0) (i64.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "div_s" (i64.const 0x8000000000000000) (i64.const -1)) "runtime: integer overflow") +(assert_trap (invoke "div_s" (i64.const 1) (i64.const 0)) "integer divide by zero") +(assert_trap (invoke "div_s" (i64.const 0) (i64.const 0)) "integer divide by zero") +(assert_trap (invoke "div_s" (i64.const 0x8000000000000000) (i64.const -1)) "integer overflow") (assert_return (invoke "div_s" (i64.const 1) (i64.const 1)) (i64.const 1)) (assert_return (invoke "div_s" (i64.const 0) (i64.const 1)) (i64.const 0)) (assert_return (invoke "div_s" (i64.const -1) (i64.const -1)) (i64.const 1)) @@ -101,8 +101,8 @@ (assert_return (invoke "div_s" (i64.const 11) (i64.const 5)) (i64.const 2)) (assert_return (invoke "div_s" (i64.const 17) (i64.const 7)) (i64.const 2)) -(assert_trap (invoke "div_u" (i64.const 1) (i64.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "div_u" (i64.const 0) (i64.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "div_u" (i64.const 1) (i64.const 0)) "integer divide by zero") +(assert_trap (invoke "div_u" (i64.const 0) (i64.const 0)) "integer divide by zero") (assert_return (invoke "div_u" (i64.const 1) (i64.const 1)) (i64.const 1)) (assert_return (invoke "div_u" (i64.const 0) (i64.const 1)) (i64.const 0)) (assert_return (invoke "div_u" (i64.const -1) (i64.const -1)) (i64.const 1)) @@ -118,8 +118,8 @@ (assert_return (invoke "div_u" (i64.const 11) (i64.const 5)) (i64.const 2)) (assert_return (invoke "div_u" (i64.const 17) (i64.const 7)) (i64.const 2)) -(assert_trap (invoke "rem_s" (i64.const 1) (i64.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "rem_s" (i64.const 0) (i64.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "rem_s" (i64.const 1) (i64.const 0)) "integer divide by zero") +(assert_trap (invoke "rem_s" (i64.const 0) (i64.const 0)) "integer divide by zero") (assert_return (invoke "rem_s" (i64.const 0x7fffffffffffffff) (i64.const -1)) (i64.const 0)) (assert_return (invoke "rem_s" (i64.const 1) (i64.const 1)) (i64.const 0)) (assert_return (invoke "rem_s" (i64.const 0) (i64.const 1)) (i64.const 0)) @@ -138,8 +138,8 @@ (assert_return (invoke "rem_s" (i64.const 11) (i64.const 5)) (i64.const 1)) (assert_return (invoke "rem_s" (i64.const 17) (i64.const 7)) (i64.const 3)) -(assert_trap (invoke "rem_u" (i64.const 1) (i64.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "rem_u" (i64.const 0) (i64.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "rem_u" (i64.const 1) (i64.const 0)) "integer divide by zero") +(assert_trap (invoke "rem_u" (i64.const 0) (i64.const 0)) "integer divide by zero") (assert_return (invoke "rem_u" (i64.const 1) (i64.const 1)) (i64.const 0)) (assert_return (invoke "rem_u" (i64.const 0) (i64.const 1)) (i64.const 0)) (assert_return (invoke "rem_u" (i64.const -1) (i64.const -1)) (i64.const 0)) diff --git a/ml-proto/test/memory_trap.wast b/ml-proto/test/memory_trap.wast index 1cd5d57808..e28321c7d3 100644 --- a/ml-proto/test/memory_trap.wast +++ b/ml-proto/test/memory_trap.wast @@ -18,15 +18,15 @@ (assert_return (invoke "store" (i32.const -4) (i32.const 42)) (i32.const 42)) (assert_return (invoke "load" (i32.const -4)) (i32.const 42)) -(assert_trap (invoke "store" (i32.const -3) (i32.const 13)) "runtime: out of bounds memory access") -(assert_trap (invoke "load" (i32.const -3)) "runtime: out of bounds memory access") -(assert_trap (invoke "store" (i32.const -2) (i32.const 13)) "runtime: out of bounds memory access") -(assert_trap (invoke "load" (i32.const -2)) "runtime: out of bounds memory access") -(assert_trap (invoke "store" (i32.const -1) (i32.const 13)) "runtime: out of bounds memory access") -(assert_trap (invoke "load" (i32.const -1)) "runtime: out of bounds memory access") -(assert_trap (invoke "store" (i32.const 0) (i32.const 13)) "runtime: out of bounds memory access") -(assert_trap (invoke "load" (i32.const 0)) "runtime: out of bounds memory access") -(assert_trap (invoke "store" (i32.const 0x80000000) (i32.const 13)) "runtime: out of bounds memory access") -(assert_trap (invoke "load" (i32.const 0x80000000)) "runtime: out of bounds memory access") -(assert_trap (invoke "grow_memory" (i32.const 3)) "runtime: grow_memory operand not multiple of page_size") -(assert_trap (invoke "overflow_memory_size") "runtime: grow_memory overflow") +(assert_trap (invoke "store" (i32.const -3) (i32.const 13)) "out of bounds memory access") +(assert_trap (invoke "load" (i32.const -3)) "out of bounds memory access") +(assert_trap (invoke "store" (i32.const -2) (i32.const 13)) "out of bounds memory access") +(assert_trap (invoke "load" (i32.const -2)) "out of bounds memory access") +(assert_trap (invoke "store" (i32.const -1) (i32.const 13)) "out of bounds memory access") +(assert_trap (invoke "load" (i32.const -1)) "out of bounds memory access") +(assert_trap (invoke "store" (i32.const 0) (i32.const 13)) "out of bounds memory access") +(assert_trap (invoke "load" (i32.const 0)) "out of bounds memory access") +(assert_trap (invoke "store" (i32.const 0x80000000) (i32.const 13)) "out of bounds memory access") +(assert_trap (invoke "load" (i32.const 0x80000000)) "out of bounds memory access") +(assert_trap (invoke "grow_memory" (i32.const 3)) "growing memory by non-multiple of page size") +(assert_trap (invoke "overflow_memory_size") "memory size exceeds implementation limit") diff --git a/ml-proto/test/resizing.wast b/ml-proto/test/resizing.wast index f38d053f60..b93a51a781 100644 --- a/ml-proto/test/resizing.wast +++ b/ml-proto/test/resizing.wast @@ -39,17 +39,17 @@ (assert_return (invoke "power_of_two") (i32.const 1)) (assert_return (invoke "size") (i32.const 0)) (assert_return (invoke "size_at_least" (i32.const 0)) (i32.const 1)) -(assert_trap (invoke "store_at_zero") "runtime: out of bounds memory access") -(assert_trap (invoke "load_at_zero") "runtime: out of bounds memory access") -(assert_trap (invoke "store_at_page_size") "runtime: out of bounds memory access") -(assert_trap (invoke "load_at_page_size") "runtime: out of bounds memory access") +(assert_trap (invoke "store_at_zero") "out of bounds memory access") +(assert_trap (invoke "load_at_zero") "out of bounds memory access") +(assert_trap (invoke "store_at_page_size") "out of bounds memory access") +(assert_trap (invoke "load_at_page_size") "out of bounds memory access") (invoke "grow" (i32.const 4)) (assert_return (invoke "size_at_least" (i32.const 4)) (i32.const 1)) (assert_return (invoke "load_at_zero") (i32.const 0)) (assert_return (invoke "store_at_zero") (i32.const 2)) (assert_return (invoke "load_at_zero") (i32.const 2)) -(assert_trap (invoke "store_at_page_size") "runtime: out of bounds memory access") -(assert_trap (invoke "load_at_page_size") "runtime: out of bounds memory access") +(assert_trap (invoke "store_at_page_size") "out of bounds memory access") +(assert_trap (invoke "load_at_page_size") "out of bounds memory access") (invoke "grow" (i32.const 4)) (assert_return (invoke "size_at_least" (i32.const 8)) (i32.const 1)) (assert_return (invoke "load_at_zero") (i32.const 2)) diff --git a/ml-proto/test/runaway-recursion.wast b/ml-proto/test/runaway-recursion.wast index 54f712dc1e..71bccd425b 100644 --- a/ml-proto/test/runaway-recursion.wast +++ b/ml-proto/test/runaway-recursion.wast @@ -13,5 +13,5 @@ (export "mutual_runaway" $a) ) -(assert_trap (invoke "runaway") "runtime: callstack exhausted") -(assert_trap (invoke "mutual_runaway") "runtime: callstack exhausted") +(assert_trap (invoke "runaway") "call stack exhausted") +(assert_trap (invoke "mutual_runaway") "call stack exhausted") diff --git a/ml-proto/test/traps.wast b/ml-proto/test/traps.wast index 84b402f339..644649d307 100644 --- a/ml-proto/test/traps.wast +++ b/ml-proto/test/traps.wast @@ -17,10 +17,10 @@ (export "no_dce.i64.div_u" $no_dce.i64.div_u) ) -(assert_trap (invoke "no_dce.i32.div_s" (i32.const 1) (i32.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "no_dce.i32.div_u" (i32.const 1) (i32.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "no_dce.i64.div_s" (i64.const 1) (i64.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "no_dce.i64.div_u" (i64.const 1) (i64.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "no_dce.i32.div_s" (i32.const 1) (i32.const 0)) "integer divide by zero") +(assert_trap (invoke "no_dce.i32.div_u" (i32.const 1) (i32.const 0)) "integer divide by zero") +(assert_trap (invoke "no_dce.i64.div_s" (i64.const 1) (i64.const 0)) "integer divide by zero") +(assert_trap (invoke "no_dce.i64.div_u" (i64.const 1) (i64.const 0)) "integer divide by zero") (module (func $no_dce.i32.rem_s (param $x i32) (param $y i32) @@ -37,10 +37,10 @@ (export "no_dce.i64.rem_u" $no_dce.i64.rem_u) ) -(assert_trap (invoke "no_dce.i32.rem_s" (i32.const 1) (i32.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "no_dce.i32.rem_u" (i32.const 1) (i32.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "no_dce.i64.rem_s" (i64.const 1) (i64.const 0)) "runtime: integer divide by zero") -(assert_trap (invoke "no_dce.i64.rem_u" (i64.const 1) (i64.const 0)) "runtime: integer divide by zero") +(assert_trap (invoke "no_dce.i32.rem_s" (i32.const 1) (i32.const 0)) "integer divide by zero") +(assert_trap (invoke "no_dce.i32.rem_u" (i32.const 1) (i32.const 0)) "integer divide by zero") +(assert_trap (invoke "no_dce.i64.rem_s" (i64.const 1) (i64.const 0)) "integer divide by zero") +(assert_trap (invoke "no_dce.i64.rem_u" (i64.const 1) (i64.const 0)) "integer divide by zero") (module (func $no_dce.i32.trunc_s_f32 (param $x f32) (i32.trunc_s/f32 (get_local $x))) @@ -62,14 +62,14 @@ (export "no_dce.i64.trunc_u_f64" $no_dce.i64.trunc_u_f64) ) -(assert_trap (invoke "no_dce.i32.trunc_s_f32" (f32.const nan)) "runtime: invalid conversion to integer") -(assert_trap (invoke "no_dce.i32.trunc_u_f32" (f32.const nan)) "runtime: invalid conversion to integer") -(assert_trap (invoke "no_dce.i32.trunc_s_f64" (f64.const nan)) "runtime: invalid conversion to integer") -(assert_trap (invoke "no_dce.i32.trunc_u_f64" (f64.const nan)) "runtime: invalid conversion to integer") -(assert_trap (invoke "no_dce.i64.trunc_s_f32" (f32.const nan)) "runtime: invalid conversion to integer") -(assert_trap (invoke "no_dce.i64.trunc_u_f32" (f32.const nan)) "runtime: invalid conversion to integer") -(assert_trap (invoke "no_dce.i64.trunc_s_f64" (f64.const nan)) "runtime: invalid conversion to integer") -(assert_trap (invoke "no_dce.i64.trunc_u_f64" (f64.const nan)) "runtime: invalid conversion to integer") +(assert_trap (invoke "no_dce.i32.trunc_s_f32" (f32.const nan)) "invalid conversion to integer") +(assert_trap (invoke "no_dce.i32.trunc_u_f32" (f32.const nan)) "invalid conversion to integer") +(assert_trap (invoke "no_dce.i32.trunc_s_f64" (f64.const nan)) "invalid conversion to integer") +(assert_trap (invoke "no_dce.i32.trunc_u_f64" (f64.const nan)) "invalid conversion to integer") +(assert_trap (invoke "no_dce.i64.trunc_s_f32" (f32.const nan)) "invalid conversion to integer") +(assert_trap (invoke "no_dce.i64.trunc_u_f32" (f32.const nan)) "invalid conversion to integer") +(assert_trap (invoke "no_dce.i64.trunc_s_f64" (f64.const nan)) "invalid conversion to integer") +(assert_trap (invoke "no_dce.i64.trunc_u_f64" (f64.const nan)) "invalid conversion to integer") (module (memory 8) @@ -84,7 +84,7 @@ (func $f64.load (param $i i32) (f64.load (get_local $i))) ) -(assert_trap (invoke "i32.load" (i32.const 8)) "runtime: out of bounds memory access") -(assert_trap (invoke "i64.load" (i32.const 8)) "runtime: out of bounds memory access") -(assert_trap (invoke "f32.load" (i32.const 8)) "runtime: out of bounds memory access") -(assert_trap (invoke "f64.load" (i32.const 8)) "runtime: out of bounds memory access") +(assert_trap (invoke "i32.load" (i32.const 8)) "out of bounds memory access") +(assert_trap (invoke "i64.load" (i32.const 8)) "out of bounds memory access") +(assert_trap (invoke "f32.load" (i32.const 8)) "out of bounds memory access") +(assert_trap (invoke "f64.load" (i32.const 8)) "out of bounds memory access")