diff --git a/src/bin/wasm2obj.rs b/src/bin/wasm2obj.rs index 03f8300525..768101a2c3 100644 --- a/src/bin/wasm2obj.rs +++ b/src/bin/wasm2obj.rs @@ -203,6 +203,11 @@ fn handle_module( }), }; let mut flag_builder = settings::builder(); + + // There are two possible traps for division, and this way + // we get the proper one if code traps. + flag_builder.enable("avoid_div_traps").unwrap(); + if enable_simd { flag_builder.enable("enable_simd").unwrap(); } diff --git a/src/bin/wasmtime.rs b/src/bin/wasmtime.rs index c590ca863d..07a08b7a43 100644 --- a/src/bin/wasmtime.rs +++ b/src/bin/wasmtime.rs @@ -258,6 +258,10 @@ fn rmain() -> Result<(), Error> { let mut flag_builder = settings::builder(); let mut features: Features = Default::default(); + // There are two possible traps for division, and this way + // we get the proper one if code traps. + flag_builder.enable("avoid_div_traps")?; + // Enable/disable producing of debug info. let debug_info = args.flag_g; diff --git a/src/bin/wast.rs b/src/bin/wast.rs index e1ee969d3d..c144f1efb0 100644 --- a/src/bin/wast.rs +++ b/src/bin/wast.rs @@ -128,6 +128,10 @@ fn main() { let mut flag_builder = settings::builder(); let mut features: Features = Default::default(); + // There are two possible traps for division, and this way + // we get the proper one if code traps. + flag_builder.enable("avoid_div_traps").unwrap(); + // Enable verifier passes in debug mode. if cfg!(debug_assertions) { flag_builder.enable("enable_verifier").unwrap(); diff --git a/tests/wast_testsuites.rs b/tests/wast_testsuites.rs index a9b5fd0a19..02d18e6eb5 100644 --- a/tests/wast_testsuites.rs +++ b/tests/wast_testsuites.rs @@ -13,6 +13,7 @@ include!(concat!(env!("OUT_DIR"), "/wast_testsuite_tests.rs")); fn native_isa() -> Box { let mut flag_builder = settings::builder(); flag_builder.enable("enable_verifier").unwrap(); + flag_builder.enable("avoid_div_traps").unwrap(); let isa_builder = cranelift_native::builder().unwrap_or_else(|_| { panic!("host machine is not a supported target"); diff --git a/wasmtime-environ/src/func_environ.rs b/wasmtime-environ/src/func_environ.rs index 591e07c406..d0bdc98e09 100644 --- a/wasmtime-environ/src/func_environ.rs +++ b/wasmtime-environ/src/func_environ.rs @@ -569,6 +569,18 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m let table_entry_addr = pos.ins().table_addr(pointer_type, table, callee, 0); + // Dereference table_entry_addr to get the function address. + let mem_flags = ir::MemFlags::trusted(); + let func_addr = pos.ins().load( + pointer_type, + mem_flags, + table_entry_addr, + i32::from(self.offsets.vmcaller_checked_anyfunc_func_ptr()), + ); + + // Check whether `func_addr` is null. + pos.ins().trapz(func_addr, ir::TrapCode::IndirectCallToNull); + // If necessary, check the signature. match self.module.table_plans[table_index].style { TableStyle::CallerChecksSignature => { @@ -599,15 +611,6 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m } } - // Dereference table_entry_addr to get the function address. - let mem_flags = ir::MemFlags::trusted(); - let func_addr = pos.ins().load( - pointer_type, - mem_flags, - table_entry_addr, - i32::from(self.offsets.vmcaller_checked_anyfunc_func_ptr()), - ); - let mut real_call_args = Vec::with_capacity(call_args.len() + 1); // First append the callee vmctx address. diff --git a/wasmtime-runtime/src/traphandlers.rs b/wasmtime-runtime/src/traphandlers.rs index 7ed29004dc..c3b4ab84e2 100644 --- a/wasmtime-runtime/src/traphandlers.rs +++ b/wasmtime-runtime/src/traphandlers.rs @@ -86,13 +86,30 @@ fn trap_message() -> String { .expect("trap_message must be called after trap occurred"); format!( - "wasm trap: code {:?}, source location: {}", - // todo print the error message from wast tests - trap_desc.trap_code, + "wasm trap: {}, source location: {}", + trap_code_to_expected_string(trap_desc.trap_code), trap_desc.source_loc, ) } +fn trap_code_to_expected_string(trap_code: ir::TrapCode) -> String { + use ir::TrapCode::*; + match trap_code { + StackOverflow => "call stack exhausted".to_string(), + HeapOutOfBounds => "out of bounds memory access".to_string(), + TableOutOfBounds => "undefined element".to_string(), + OutOfBounds => "out of bounds".to_string(), // Note: not covered by the test suite + IndirectCallToNull => "uninitialized element".to_string(), + BadSignature => "indirect call type mismatch".to_string(), + IntegerOverflow => "integer overflow".to_string(), + IntegerDivisionByZero => "integer divide by zero".to_string(), + BadConversionToInteger => "invalid conversion to integer".to_string(), + UnreachableCodeReached => "unreachable".to_string(), + Interrupt => "interrupt".to_string(), // Note: not covered by the test suite + User(x) => format!("user trap {}", x), // Note: not covered by the test suite + } +} + /// Call the wasm function pointed to by `callee`. `values_vec` points to /// a buffer which holds the incoming arguments, and to which the outgoing /// return values will be written. diff --git a/wasmtime-wast/src/wast.rs b/wasmtime-wast/src/wast.rs index 040fc8cb05..966b4ae4e5 100644 --- a/wasmtime-wast/src/wast.rs +++ b/wasmtime-wast/src/wast.rs @@ -289,10 +289,16 @@ impl WastContext { ActionOutcome::Trapped { message: trap_message, } => { - println!( - "{}:{}: TODO: Check the assert_trap message: expected {}, got {}", - filename, line, message, trap_message - ); + if !trap_message.contains(&message) { + return Err(WastFileError { + filename: filename.to_string(), + line, + error: WastError::Assert(format!( + "expected {}, got {}", + message, trap_message + )), + }); + } } } } @@ -315,10 +321,16 @@ impl WastContext { ActionOutcome::Trapped { message: trap_message, } => { - println!( - "{}:{}: TODO: Check the assert_exhaustion message: expected {}, got {}", - filename, line, message, trap_message - ); + if !trap_message.contains(&message) { + return Err(WastFileError { + filename: filename.to_string(), + line, + error: WastError::Assert(format!( + "expected exhaustion with {}, got {}", + message, trap_message + )), + }); + } } } }