1 use wasmtime::*; 2 use wasmtime_test_macros::wasmtime_test; 3 4 #[wasmtime_test(wasm_features(exceptions))] 5 #[cfg_attr(miri, ignore)] 6 fn basic_throw(config: &mut Config) -> Result<()> { 7 let engine = Engine::new(config)?; 8 let mut store = Store::new(&engine, ()); 9 10 let module = Module::new( 11 &engine, 12 r#" 13 (module 14 (tag $e0 (param i32 i64)) 15 16 (func $throw (param i32 i64) 17 (throw $e0 (local.get 0) (local.get 1))) 18 19 (func $catch (export "catch") (param i32 i64) (result i32 i64) 20 21 (block $b (result i32 i64) 22 (try_table (result i32 i64) 23 (catch $e0 $b) 24 (call $throw (local.get 0) (local.get 1)) 25 (i32.const 42) 26 (i64.const 100))))) 27 "#, 28 )?; 29 30 let instance = Instance::new(&mut store, &module, &[])?; 31 let func = instance.get_func(&mut store, "catch").unwrap(); 32 let mut results = [Val::I32(0), Val::I64(0)]; 33 func.call(&mut store, &[Val::I32(1), Val::I64(2)], &mut results[..])?; 34 assert!(matches!(results[0], Val::I32(1))); 35 assert!(matches!(results[1], Val::I64(2))); 36 37 Ok(()) 38 } 39 40 #[wasmtime_test(wasm_features(exceptions))] 41 #[cfg_attr(miri, ignore)] 42 fn dynamic_tags(config: &mut Config) -> Result<()> { 43 let engine = Engine::new(config)?; 44 let mut store = Store::new(&engine, ()); 45 46 let module = Module::new( 47 &engine, 48 r#" 49 (module 50 (import "test" "e0" (tag $e0 (param i32 i64))) 51 (import "test" "e1" (tag $e1 (param i32 i64))) 52 53 (func $throw_e1 (param i32 i64) 54 (throw $e1 (local.get 0) (local.get 1))) 55 56 (func $catch (export "catch") (param i32 i64) (result i32 i64 i32) 57 (block $b1 (result i32 i64) 58 (block $b0 (result i32 i64) 59 (try_table (result i32 i64) 60 (catch $e0 $b0) 61 (catch $e1 $b1) 62 (call $throw_e1 (local.get 0) (local.get 1)) 63 (unreachable))) 64 (i32.const 0) 65 (return)) 66 (i32.const 1) 67 (return))) 68 "#, 69 )?; 70 71 let functy = FuncType::new(&engine, [ValType::I32, ValType::I64], []); 72 let tagty = TagType::new(functy); 73 let tag0 = Tag::new(&mut store, &tagty)?; 74 let tag1 = Tag::new(&mut store, &tagty)?; 75 76 // Instantiate with two different tags -- second catch-clause 77 // should match (on $e1). 78 let instance1 = Instance::new(&mut store, &module, &[Extern::Tag(tag0), Extern::Tag(tag1)])?; 79 let func1 = instance1.get_func(&mut store, "catch").unwrap(); 80 let mut results = [Val::I32(0), Val::I64(0), Val::I32(0)]; 81 func1.call(&mut store, &[Val::I32(1), Val::I64(2)], &mut results[..])?; 82 assert!(matches!(results[0], Val::I32(1))); 83 assert!(matches!(results[1], Val::I64(2))); 84 assert!(matches!(results[2], Val::I32(1))); 85 86 // Instantiate with two imports of the same tag -- now first 87 // catch-clause should match (on $e0, since $e0 is an alias to 88 // $e1). 89 let instance2 = Instance::new(&mut store, &module, &[Extern::Tag(tag0), Extern::Tag(tag0)])?; 90 let func2 = instance2.get_func(&mut store, "catch").unwrap(); 91 let mut results = [Val::I32(0), Val::I64(0), Val::I32(0)]; 92 func2.call(&mut store, &[Val::I32(1), Val::I64(2)], &mut results[..])?; 93 assert!(matches!(results[0], Val::I32(1))); 94 assert!(matches!(results[1], Val::I64(2))); 95 assert!(matches!(results[2], Val::I32(0))); 96 97 Ok(()) 98 } 99 100 #[wasmtime_test(wasm_features(exceptions))] 101 #[cfg_attr(miri, ignore)] 102 fn exception_escape_to_host(config: &mut Config) -> Result<()> { 103 let engine = Engine::new(config)?; 104 let mut store = Store::new(&engine, ()); 105 106 let module = Module::new( 107 &engine, 108 r#" 109 (module 110 (import "test" "e0" (tag $e0 (param i32))) 111 112 (func $throw (export "throw") 113 (throw $e0 (i32.const 42)))) 114 "#, 115 )?; 116 117 let functy = FuncType::new(&engine, [ValType::I32], []); 118 let tagty = TagType::new(functy); 119 let tag = Tag::new(&mut store, &tagty)?; 120 let instance = Instance::new(&mut store, &module, &[Extern::Tag(tag)])?; 121 let func = instance.get_func(&mut store, "throw").unwrap(); 122 let mut results = []; 123 let result = func.call(&mut store, &[], &mut results[..]); 124 assert!(result.is_err()); 125 assert!(result.unwrap_err().is::<ThrownException>()); 126 let exn = store.take_pending_exception().unwrap(); 127 let exntag = exn.tag(&mut store)?; 128 assert!(Tag::eq(&exntag, &tag, &store)); 129 130 Ok(()) 131 } 132 133 #[wasmtime_test(wasm_features(exceptions))] 134 #[cfg_attr(miri, ignore)] 135 fn exception_from_host(config: &mut Config) -> Result<()> { 136 let engine = Engine::new(config)?; 137 let mut store = Store::new(&engine, ()); 138 139 let module = Module::new( 140 &engine, 141 r#" 142 (module 143 (import "test" "e0" (tag $e0 (param i32))) 144 (import "test" "f" (func $f (param i32))) 145 146 (func $catch (export "catch") (result i32) 147 (block $b (result i32) 148 (try_table (result i32) (catch $e0 $b) 149 i32.const 42 150 call $f 151 i32.const 0)))) 152 "#, 153 )?; 154 155 let functy = FuncType::new(&engine, [ValType::I32], []); 156 let tagty = TagType::new(functy.clone()); 157 let exnty = ExnType::from_tag_type(&tagty).unwrap(); 158 let exnpre = ExnRefPre::new(&mut store, exnty); 159 let tag = Tag::new(&mut store, &tagty)?; 160 let extfunc = Func::new(&mut store, functy, move |mut caller, args, _rets| { 161 let exn = ExnRef::new( 162 &mut caller, 163 &exnpre, 164 &tag, 165 &[Val::I32(args[0].unwrap_i32())], 166 ) 167 .unwrap(); 168 caller.as_context_mut().throw(exn)?; 169 Ok(()) 170 }); 171 let instance = Instance::new( 172 &mut store, 173 &module, 174 &[Extern::Tag(tag), Extern::Func(extfunc)], 175 )?; 176 let func = instance.get_func(&mut store, "catch").unwrap(); 177 let mut results = [Val::null_any_ref()]; 178 func.call(&mut store, &[], &mut results[..])?; 179 assert_eq!(results[0].unwrap_i32(), 42); 180 181 Ok(()) 182 } 183 184 #[wasmtime_test(wasm_features(exceptions))] 185 fn exception_across_no_wasm(config: &mut Config) -> Result<()> { 186 let engine = Engine::new(config)?; 187 let mut store = Store::new(&engine, ()); 188 189 let functy = FuncType::new(&engine, [ValType::I32], []); 190 let tagty = TagType::new(functy.clone()); 191 let exnty = ExnType::from_tag_type(&tagty).unwrap(); 192 let exnpre = ExnRefPre::new(&mut store, exnty); 193 let tag = Tag::new(&mut store, &tagty)?; 194 let extfunc = Func::new(&mut store, functy, move |mut caller, args, _rets| { 195 let exn = ExnRef::new( 196 &mut caller, 197 &exnpre, 198 &tag, 199 &[Val::I32(args[0].unwrap_i32())], 200 ) 201 .unwrap(); 202 caller.as_context_mut().throw(exn)?; 203 Ok(()) 204 }); 205 let mut results = []; 206 let result = extfunc.call(&mut store, &[Val::I32(42)], &mut results[..]); 207 assert!(result.is_err() && result.unwrap_err().downcast::<ThrownException>().is_ok()); 208 let exn = store.take_pending_exception().unwrap(); 209 let exntag = exn.tag(&mut store)?; 210 assert!(Tag::eq(&exntag, &tag, &store)); 211 assert_eq!(exn.field(&mut store, 0)?.unwrap_i32(), 42); 212 213 Ok(()) 214 } 215