1 use super::{TypedFuncExt, REALLOC_AND_FREE}; 2 use anyhow::Result; 3 use std::rc::Rc; 4 use std::sync::Arc; 5 use wasmtime::component::*; 6 use wasmtime::{Store, StoreContextMut, Trap, TrapCode}; 7 8 const CANON_32BIT_NAN: u32 = 0b01111111110000000000000000000000; 9 const CANON_64BIT_NAN: u64 = 0b0111111111111000000000000000000000000000000000000000000000000000; 10 11 #[test] 12 fn thunks() -> Result<()> { 13 let component = r#" 14 (component 15 (core module $m 16 (func (export "thunk")) 17 (func (export "thunk-trap") unreachable) 18 ) 19 (core instance $i (instantiate $m)) 20 (func (export "thunk") 21 (canon lift (core func $i "thunk")) 22 ) 23 (func (export "thunk-trap") 24 (canon lift (core func $i "thunk-trap")) 25 ) 26 ) 27 "#; 28 29 let engine = super::engine(); 30 let component = Component::new(&engine, component)?; 31 let mut store = Store::new(&engine, ()); 32 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 33 instance 34 .get_typed_func::<(), (), _>(&mut store, "thunk")? 35 .call_and_post_return(&mut store, ())?; 36 let err = instance 37 .get_typed_func::<(), (), _>(&mut store, "thunk-trap")? 38 .call(&mut store, ()) 39 .unwrap_err(); 40 assert!(err.downcast::<Trap>()?.trap_code() == Some(TrapCode::UnreachableCodeReached)); 41 42 Ok(()) 43 } 44 45 #[test] 46 fn typecheck() -> Result<()> { 47 let component = r#" 48 (component 49 (core module $m 50 (func (export "thunk")) 51 (func (export "take-string") (param i32 i32)) 52 (func (export "two-args") (param i32 i32 i32)) 53 (func (export "ret-one") (result i32) unreachable) 54 55 (memory (export "memory") 1) 56 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 57 unreachable) 58 ) 59 (core instance $i (instantiate (module $m))) 60 (func (export "thunk") 61 (canon lift (core func $i "thunk")) 62 ) 63 (func (export "tuple-thunk") (param (tuple)) (result (tuple)) 64 (canon lift (core func $i "thunk")) 65 ) 66 (func (export "take-string") (param string) 67 (canon lift (core func $i "take-string") (memory $i "memory") (realloc (func $i "realloc"))) 68 ) 69 (func (export "take-two-args") (param s32) (param (list u8)) 70 (canon lift (core func $i "two-args") (memory $i "memory") (realloc (func $i "realloc"))) 71 ) 72 (func (export "ret-tuple") (result (tuple u8 s8)) 73 (canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc"))) 74 ) 75 (func (export "ret-tuple1") (result (tuple u32)) 76 (canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc"))) 77 ) 78 (func (export "ret-string") (result string) 79 (canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc"))) 80 ) 81 (func (export "ret-list-u8") (result (list u8)) 82 (canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc"))) 83 ) 84 ) 85 "#; 86 87 let engine = super::engine(); 88 let component = Component::new(&engine, component)?; 89 let mut store = Store::new(&engine, ()); 90 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 91 let thunk = instance.get_func(&mut store, "thunk").unwrap(); 92 let tuple_thunk = instance.get_func(&mut store, "tuple-thunk").unwrap(); 93 let take_string = instance.get_func(&mut store, "take-string").unwrap(); 94 let take_two_args = instance.get_func(&mut store, "take-two-args").unwrap(); 95 let ret_tuple = instance.get_func(&mut store, "ret-tuple").unwrap(); 96 let ret_tuple1 = instance.get_func(&mut store, "ret-tuple1").unwrap(); 97 let ret_string = instance.get_func(&mut store, "ret-string").unwrap(); 98 let ret_list_u8 = instance.get_func(&mut store, "ret-list-u8").unwrap(); 99 assert!(thunk.typed::<(), u32, _>(&store).is_err()); 100 assert!(thunk.typed::<(u32,), (), _>(&store).is_err()); 101 assert!(thunk.typed::<(), (), _>(&store).is_ok()); 102 assert!(tuple_thunk.typed::<(), (), _>(&store).is_err()); 103 assert!(tuple_thunk.typed::<((),), (), _>(&store).is_ok()); 104 assert!(take_string.typed::<(), (), _>(&store).is_err()); 105 assert!(take_string.typed::<(String,), (), _>(&store).is_ok()); 106 assert!(take_string.typed::<(&str,), (), _>(&store).is_ok()); 107 assert!(take_string.typed::<(&[u8],), (), _>(&store).is_err()); 108 assert!(take_two_args.typed::<(), (), _>(&store).is_err()); 109 assert!(take_two_args.typed::<(i32, &[u8]), u32, _>(&store).is_err()); 110 assert!(take_two_args.typed::<(u32, &[u8]), (), _>(&store).is_err()); 111 assert!(take_two_args.typed::<(i32, &[u8]), (), _>(&store).is_ok()); 112 assert!(ret_tuple.typed::<(), (), _>(&store).is_err()); 113 assert!(ret_tuple.typed::<(), (u8,), _>(&store).is_err()); 114 assert!(ret_tuple.typed::<(), (u8, i8), _>(&store).is_ok()); 115 assert!(ret_tuple1.typed::<(), (u32,), _>(&store).is_ok()); 116 assert!(ret_tuple1.typed::<(), u32, _>(&store).is_err()); 117 assert!(ret_string.typed::<(), (), _>(&store).is_err()); 118 assert!(ret_string.typed::<(), WasmStr, _>(&store).is_ok()); 119 assert!(ret_list_u8.typed::<(), WasmList<u16>, _>(&store).is_err()); 120 assert!(ret_list_u8.typed::<(), WasmList<i8>, _>(&store).is_err()); 121 assert!(ret_list_u8.typed::<(), WasmList<u8>, _>(&store).is_ok()); 122 123 Ok(()) 124 } 125 126 #[test] 127 fn integers() -> Result<()> { 128 let component = r#" 129 (component 130 (core module $m 131 (func (export "take-i32-100") (param i32) 132 local.get 0 133 i32.const 100 134 i32.eq 135 br_if 0 136 unreachable 137 ) 138 (func (export "take-i64-100") (param i64) 139 local.get 0 140 i64.const 100 141 i64.eq 142 br_if 0 143 unreachable 144 ) 145 (func (export "ret-i32-0") (result i32) i32.const 0) 146 (func (export "ret-i64-0") (result i64) i64.const 0) 147 (func (export "ret-i32-minus-1") (result i32) i32.const -1) 148 (func (export "ret-i64-minus-1") (result i64) i64.const -1) 149 (func (export "ret-i32-100000") (result i32) i32.const 100000) 150 ) 151 (core instance $i (instantiate (module $m))) 152 (func (export "take-u8") (param u8) (canon lift (core func $i "take-i32-100"))) 153 (func (export "take-s8") (param s8) (canon lift (core func $i "take-i32-100"))) 154 (func (export "take-u16") (param u16) (canon lift (core func $i "take-i32-100"))) 155 (func (export "take-s16") (param s16) (canon lift (core func $i "take-i32-100"))) 156 (func (export "take-u32") (param u32) (canon lift (core func $i "take-i32-100"))) 157 (func (export "take-s32") (param s32) (canon lift (core func $i "take-i32-100"))) 158 (func (export "take-u64") (param u64) (canon lift (core func $i "take-i64-100"))) 159 (func (export "take-s64") (param s64) (canon lift (core func $i "take-i64-100"))) 160 161 (func (export "ret-u8") (result u8) (canon lift (core func $i "ret-i32-0"))) 162 (func (export "ret-s8") (result s8) (canon lift (core func $i "ret-i32-0"))) 163 (func (export "ret-u16") (result u16) (canon lift (core func $i "ret-i32-0"))) 164 (func (export "ret-s16") (result s16) (canon lift (core func $i "ret-i32-0"))) 165 (func (export "ret-u32") (result u32) (canon lift (core func $i "ret-i32-0"))) 166 (func (export "ret-s32") (result s32) (canon lift (core func $i "ret-i32-0"))) 167 (func (export "ret-u64") (result u64) (canon lift (core func $i "ret-i64-0"))) 168 (func (export "ret-s64") (result s64) (canon lift (core func $i "ret-i64-0"))) 169 170 (func (export "retm1-u8") (result u8) (canon lift (core func $i "ret-i32-minus-1"))) 171 (func (export "retm1-s8") (result s8) (canon lift (core func $i "ret-i32-minus-1"))) 172 (func (export "retm1-u16") (result u16) (canon lift (core func $i "ret-i32-minus-1"))) 173 (func (export "retm1-s16") (result s16) (canon lift (core func $i "ret-i32-minus-1"))) 174 (func (export "retm1-u32") (result u32) (canon lift (core func $i "ret-i32-minus-1"))) 175 (func (export "retm1-s32") (result s32) (canon lift (core func $i "ret-i32-minus-1"))) 176 (func (export "retm1-u64") (result u64) (canon lift (core func $i "ret-i64-minus-1"))) 177 (func (export "retm1-s64") (result s64) (canon lift (core func $i "ret-i64-minus-1"))) 178 179 (func (export "retbig-u8") (result u8) (canon lift (core func $i "ret-i32-100000"))) 180 (func (export "retbig-s8") (result s8) (canon lift (core func $i "ret-i32-100000"))) 181 (func (export "retbig-u16") (result u16) (canon lift (core func $i "ret-i32-100000"))) 182 (func (export "retbig-s16") (result s16) (canon lift (core func $i "ret-i32-100000"))) 183 (func (export "retbig-u32") (result u32) (canon lift (core func $i "ret-i32-100000"))) 184 (func (export "retbig-s32") (result s32) (canon lift (core func $i "ret-i32-100000"))) 185 ) 186 "#; 187 188 let engine = super::engine(); 189 let component = Component::new(&engine, component)?; 190 let mut store = Store::new(&engine, ()); 191 let new_instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component); 192 let instance = new_instance(&mut store)?; 193 194 // Passing in 100 is valid for all primitives 195 instance 196 .get_typed_func::<(u8,), (), _>(&mut store, "take-u8")? 197 .call_and_post_return(&mut store, (100,))?; 198 instance 199 .get_typed_func::<(i8,), (), _>(&mut store, "take-s8")? 200 .call_and_post_return(&mut store, (100,))?; 201 instance 202 .get_typed_func::<(u16,), (), _>(&mut store, "take-u16")? 203 .call_and_post_return(&mut store, (100,))?; 204 instance 205 .get_typed_func::<(i16,), (), _>(&mut store, "take-s16")? 206 .call_and_post_return(&mut store, (100,))?; 207 instance 208 .get_typed_func::<(u32,), (), _>(&mut store, "take-u32")? 209 .call_and_post_return(&mut store, (100,))?; 210 instance 211 .get_typed_func::<(i32,), (), _>(&mut store, "take-s32")? 212 .call_and_post_return(&mut store, (100,))?; 213 instance 214 .get_typed_func::<(u64,), (), _>(&mut store, "take-u64")? 215 .call_and_post_return(&mut store, (100,))?; 216 instance 217 .get_typed_func::<(i64,), (), _>(&mut store, "take-s64")? 218 .call_and_post_return(&mut store, (100,))?; 219 220 // This specific wasm instance traps if any value other than 100 is passed 221 new_instance(&mut store)? 222 .get_typed_func::<(u8,), (), _>(&mut store, "take-u8")? 223 .call(&mut store, (101,)) 224 .unwrap_err() 225 .downcast::<Trap>()?; 226 new_instance(&mut store)? 227 .get_typed_func::<(i8,), (), _>(&mut store, "take-s8")? 228 .call(&mut store, (101,)) 229 .unwrap_err() 230 .downcast::<Trap>()?; 231 new_instance(&mut store)? 232 .get_typed_func::<(u16,), (), _>(&mut store, "take-u16")? 233 .call(&mut store, (101,)) 234 .unwrap_err() 235 .downcast::<Trap>()?; 236 new_instance(&mut store)? 237 .get_typed_func::<(i16,), (), _>(&mut store, "take-s16")? 238 .call(&mut store, (101,)) 239 .unwrap_err() 240 .downcast::<Trap>()?; 241 new_instance(&mut store)? 242 .get_typed_func::<(u32,), (), _>(&mut store, "take-u32")? 243 .call(&mut store, (101,)) 244 .unwrap_err() 245 .downcast::<Trap>()?; 246 new_instance(&mut store)? 247 .get_typed_func::<(i32,), (), _>(&mut store, "take-s32")? 248 .call(&mut store, (101,)) 249 .unwrap_err() 250 .downcast::<Trap>()?; 251 new_instance(&mut store)? 252 .get_typed_func::<(u64,), (), _>(&mut store, "take-u64")? 253 .call(&mut store, (101,)) 254 .unwrap_err() 255 .downcast::<Trap>()?; 256 new_instance(&mut store)? 257 .get_typed_func::<(i64,), (), _>(&mut store, "take-s64")? 258 .call(&mut store, (101,)) 259 .unwrap_err() 260 .downcast::<Trap>()?; 261 262 // Zero can be returned as any integer 263 assert_eq!( 264 instance 265 .get_typed_func::<(), u8, _>(&mut store, "ret-u8")? 266 .call_and_post_return(&mut store, ())?, 267 0 268 ); 269 assert_eq!( 270 instance 271 .get_typed_func::<(), i8, _>(&mut store, "ret-s8")? 272 .call_and_post_return(&mut store, ())?, 273 0 274 ); 275 assert_eq!( 276 instance 277 .get_typed_func::<(), u16, _>(&mut store, "ret-u16")? 278 .call_and_post_return(&mut store, ())?, 279 0 280 ); 281 assert_eq!( 282 instance 283 .get_typed_func::<(), i16, _>(&mut store, "ret-s16")? 284 .call_and_post_return(&mut store, ())?, 285 0 286 ); 287 assert_eq!( 288 instance 289 .get_typed_func::<(), u32, _>(&mut store, "ret-u32")? 290 .call_and_post_return(&mut store, ())?, 291 0 292 ); 293 assert_eq!( 294 instance 295 .get_typed_func::<(), i32, _>(&mut store, "ret-s32")? 296 .call_and_post_return(&mut store, ())?, 297 0 298 ); 299 assert_eq!( 300 instance 301 .get_typed_func::<(), u64, _>(&mut store, "ret-u64")? 302 .call_and_post_return(&mut store, ())?, 303 0 304 ); 305 assert_eq!( 306 instance 307 .get_typed_func::<(), i64, _>(&mut store, "ret-s64")? 308 .call_and_post_return(&mut store, ())?, 309 0 310 ); 311 312 // Returning -1 should reinterpret the bytes as defined by each type. 313 assert_eq!( 314 instance 315 .get_typed_func::<(), u8, _>(&mut store, "retm1-u8")? 316 .call_and_post_return(&mut store, ())?, 317 0xff 318 ); 319 assert_eq!( 320 instance 321 .get_typed_func::<(), i8, _>(&mut store, "retm1-s8")? 322 .call_and_post_return(&mut store, ())?, 323 -1 324 ); 325 assert_eq!( 326 instance 327 .get_typed_func::<(), u16, _>(&mut store, "retm1-u16")? 328 .call_and_post_return(&mut store, ())?, 329 0xffff 330 ); 331 assert_eq!( 332 instance 333 .get_typed_func::<(), i16, _>(&mut store, "retm1-s16")? 334 .call_and_post_return(&mut store, ())?, 335 -1 336 ); 337 assert_eq!( 338 instance 339 .get_typed_func::<(), u32, _>(&mut store, "retm1-u32")? 340 .call_and_post_return(&mut store, ())?, 341 0xffffffff 342 ); 343 assert_eq!( 344 instance 345 .get_typed_func::<(), i32, _>(&mut store, "retm1-s32")? 346 .call_and_post_return(&mut store, ())?, 347 -1 348 ); 349 assert_eq!( 350 instance 351 .get_typed_func::<(), u64, _>(&mut store, "retm1-u64")? 352 .call_and_post_return(&mut store, ())?, 353 0xffffffff_ffffffff 354 ); 355 assert_eq!( 356 instance 357 .get_typed_func::<(), i64, _>(&mut store, "retm1-s64")? 358 .call_and_post_return(&mut store, ())?, 359 -1 360 ); 361 362 // Returning 100000 should chop off bytes as necessary 363 let ret: u32 = 100000; 364 assert_eq!( 365 instance 366 .get_typed_func::<(), u8, _>(&mut store, "retbig-u8")? 367 .call_and_post_return(&mut store, ())?, 368 ret as u8, 369 ); 370 assert_eq!( 371 instance 372 .get_typed_func::<(), i8, _>(&mut store, "retbig-s8")? 373 .call_and_post_return(&mut store, ())?, 374 ret as i8, 375 ); 376 assert_eq!( 377 instance 378 .get_typed_func::<(), u16, _>(&mut store, "retbig-u16")? 379 .call_and_post_return(&mut store, ())?, 380 ret as u16, 381 ); 382 assert_eq!( 383 instance 384 .get_typed_func::<(), i16, _>(&mut store, "retbig-s16")? 385 .call_and_post_return(&mut store, ())?, 386 ret as i16, 387 ); 388 assert_eq!( 389 instance 390 .get_typed_func::<(), u32, _>(&mut store, "retbig-u32")? 391 .call_and_post_return(&mut store, ())?, 392 ret, 393 ); 394 assert_eq!( 395 instance 396 .get_typed_func::<(), i32, _>(&mut store, "retbig-s32")? 397 .call_and_post_return(&mut store, ())?, 398 ret as i32, 399 ); 400 401 Ok(()) 402 } 403 404 #[test] 405 fn type_layers() -> Result<()> { 406 let component = r#" 407 (component 408 (core module $m 409 (func (export "take-i32-100") (param i32) 410 local.get 0 411 i32.const 2 412 i32.eq 413 br_if 0 414 unreachable 415 ) 416 ) 417 (core instance $i (instantiate $m)) 418 (func (export "take-u32") (param u32) (canon lift (core func $i "take-i32-100"))) 419 ) 420 "#; 421 422 let engine = super::engine(); 423 let component = Component::new(&engine, component)?; 424 let mut store = Store::new(&engine, ()); 425 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 426 427 instance 428 .get_typed_func::<(Box<u32>,), (), _>(&mut store, "take-u32")? 429 .call_and_post_return(&mut store, (Box::new(2),))?; 430 instance 431 .get_typed_func::<(&u32,), (), _>(&mut store, "take-u32")? 432 .call_and_post_return(&mut store, (&2,))?; 433 instance 434 .get_typed_func::<(Rc<u32>,), (), _>(&mut store, "take-u32")? 435 .call_and_post_return(&mut store, (Rc::new(2),))?; 436 instance 437 .get_typed_func::<(Arc<u32>,), (), _>(&mut store, "take-u32")? 438 .call_and_post_return(&mut store, (Arc::new(2),))?; 439 instance 440 .get_typed_func::<(&Box<Arc<Rc<u32>>>,), (), _>(&mut store, "take-u32")? 441 .call_and_post_return(&mut store, (&Box::new(Arc::new(Rc::new(2))),))?; 442 443 Ok(()) 444 } 445 446 #[test] 447 fn floats() -> Result<()> { 448 let component = r#" 449 (component 450 (core module $m 451 (func (export "i32.reinterpret_f32") (param f32) (result i32) 452 local.get 0 453 i32.reinterpret_f32 454 ) 455 (func (export "i64.reinterpret_f64") (param f64) (result i64) 456 local.get 0 457 i64.reinterpret_f64 458 ) 459 (func (export "f32.reinterpret_i32") (param i32) (result f32) 460 local.get 0 461 f32.reinterpret_i32 462 ) 463 (func (export "f64.reinterpret_i64") (param i64) (result f64) 464 local.get 0 465 f64.reinterpret_i64 466 ) 467 ) 468 (core instance $i (instantiate $m)) 469 470 (func (export "f32-to-u32") (param float32) (result u32) 471 (canon lift (core func $i "i32.reinterpret_f32")) 472 ) 473 (func (export "f64-to-u64") (param float64) (result u64) 474 (canon lift (core func $i "i64.reinterpret_f64")) 475 ) 476 (func (export "u32-to-f32") (param u32) (result float32) 477 (canon lift (core func $i "f32.reinterpret_i32")) 478 ) 479 (func (export "u64-to-f64") (param u64) (result float64) 480 (canon lift (core func $i "f64.reinterpret_i64")) 481 ) 482 ) 483 "#; 484 485 let engine = super::engine(); 486 let component = Component::new(&engine, component)?; 487 let mut store = Store::new(&engine, ()); 488 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 489 let f32_to_u32 = instance.get_typed_func::<(f32,), u32, _>(&mut store, "f32-to-u32")?; 490 let f64_to_u64 = instance.get_typed_func::<(f64,), u64, _>(&mut store, "f64-to-u64")?; 491 let u32_to_f32 = instance.get_typed_func::<(u32,), f32, _>(&mut store, "u32-to-f32")?; 492 let u64_to_f64 = instance.get_typed_func::<(u64,), f64, _>(&mut store, "u64-to-f64")?; 493 494 assert_eq!(f32_to_u32.call(&mut store, (1.0,))?, 1.0f32.to_bits()); 495 f32_to_u32.post_return(&mut store)?; 496 assert_eq!(f64_to_u64.call(&mut store, (2.0,))?, 2.0f64.to_bits()); 497 f64_to_u64.post_return(&mut store)?; 498 assert_eq!(u32_to_f32.call(&mut store, (3.0f32.to_bits(),))?, 3.0); 499 u32_to_f32.post_return(&mut store)?; 500 assert_eq!(u64_to_f64.call(&mut store, (4.0f64.to_bits(),))?, 4.0); 501 u64_to_f64.post_return(&mut store)?; 502 503 assert_eq!( 504 u32_to_f32 505 .call(&mut store, (CANON_32BIT_NAN | 1,))? 506 .to_bits(), 507 CANON_32BIT_NAN 508 ); 509 u32_to_f32.post_return(&mut store)?; 510 assert_eq!( 511 u64_to_f64 512 .call(&mut store, (CANON_64BIT_NAN | 1,))? 513 .to_bits(), 514 CANON_64BIT_NAN 515 ); 516 u64_to_f64.post_return(&mut store)?; 517 518 assert_eq!( 519 f32_to_u32.call(&mut store, (f32::from_bits(CANON_32BIT_NAN | 1),))?, 520 CANON_32BIT_NAN 521 ); 522 f32_to_u32.post_return(&mut store)?; 523 assert_eq!( 524 f64_to_u64.call(&mut store, (f64::from_bits(CANON_64BIT_NAN | 1),))?, 525 CANON_64BIT_NAN 526 ); 527 f64_to_u64.post_return(&mut store)?; 528 529 Ok(()) 530 } 531 532 #[test] 533 fn bools() -> Result<()> { 534 let component = r#" 535 (component 536 (core module $m 537 (func (export "pass") (param i32) (result i32) local.get 0) 538 ) 539 (core instance $i (instantiate $m)) 540 541 (func (export "u32-to-bool") (param u32) (result bool) 542 (canon lift (core func $i "pass")) 543 ) 544 (func (export "bool-to-u32") (param bool) (result u32) 545 (canon lift (core func $i "pass")) 546 ) 547 ) 548 "#; 549 550 let engine = super::engine(); 551 let component = Component::new(&engine, component)?; 552 let mut store = Store::new(&engine, ()); 553 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 554 let u32_to_bool = instance.get_typed_func::<(u32,), bool, _>(&mut store, "u32-to-bool")?; 555 let bool_to_u32 = instance.get_typed_func::<(bool,), u32, _>(&mut store, "bool-to-u32")?; 556 557 assert_eq!(bool_to_u32.call(&mut store, (false,))?, 0); 558 bool_to_u32.post_return(&mut store)?; 559 assert_eq!(bool_to_u32.call(&mut store, (true,))?, 1); 560 bool_to_u32.post_return(&mut store)?; 561 assert_eq!(u32_to_bool.call(&mut store, (0,))?, false); 562 u32_to_bool.post_return(&mut store)?; 563 assert_eq!(u32_to_bool.call(&mut store, (1,))?, true); 564 u32_to_bool.post_return(&mut store)?; 565 assert_eq!(u32_to_bool.call(&mut store, (2,))?, true); 566 u32_to_bool.post_return(&mut store)?; 567 568 Ok(()) 569 } 570 571 #[test] 572 fn chars() -> Result<()> { 573 let component = r#" 574 (component 575 (core module $m 576 (func (export "pass") (param i32) (result i32) local.get 0) 577 ) 578 (core instance $i (instantiate $m)) 579 580 (func (export "u32-to-char") (param u32) (result char) 581 (canon lift (core func $i "pass")) 582 ) 583 (func (export "char-to-u32") (param char) (result u32) 584 (canon lift (core func $i "pass")) 585 ) 586 ) 587 "#; 588 589 let engine = super::engine(); 590 let component = Component::new(&engine, component)?; 591 let mut store = Store::new(&engine, ()); 592 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 593 let u32_to_char = instance.get_typed_func::<(u32,), char, _>(&mut store, "u32-to-char")?; 594 let char_to_u32 = instance.get_typed_func::<(char,), u32, _>(&mut store, "char-to-u32")?; 595 596 let mut roundtrip = |x: char| -> Result<()> { 597 assert_eq!(char_to_u32.call(&mut store, (x,))?, x as u32); 598 char_to_u32.post_return(&mut store)?; 599 assert_eq!(u32_to_char.call(&mut store, (x as u32,))?, x); 600 u32_to_char.post_return(&mut store)?; 601 Ok(()) 602 }; 603 604 roundtrip('x')?; 605 roundtrip('a')?; 606 roundtrip('\0')?; 607 roundtrip('\n')?; 608 roundtrip('')?; 609 610 let u32_to_char = |store: &mut Store<()>| { 611 Linker::new(&engine) 612 .instantiate(&mut *store, &component)? 613 .get_typed_func::<(u32,), char, _>(&mut *store, "u32-to-char") 614 }; 615 let err = u32_to_char(&mut store)? 616 .call(&mut store, (0xd800,)) 617 .unwrap_err(); 618 assert!(err.to_string().contains("integer out of range"), "{}", err); 619 let err = u32_to_char(&mut store)? 620 .call(&mut store, (0xdfff,)) 621 .unwrap_err(); 622 assert!(err.to_string().contains("integer out of range"), "{}", err); 623 let err = u32_to_char(&mut store)? 624 .call(&mut store, (0x110000,)) 625 .unwrap_err(); 626 assert!(err.to_string().contains("integer out of range"), "{}", err); 627 let err = u32_to_char(&mut store)? 628 .call(&mut store, (u32::MAX,)) 629 .unwrap_err(); 630 assert!(err.to_string().contains("integer out of range"), "{}", err); 631 632 Ok(()) 633 } 634 635 #[test] 636 fn tuple_result() -> Result<()> { 637 let component = r#" 638 (component 639 (core module $m 640 (memory (export "memory") 1) 641 (func (export "foo") (param i32 i32 f32 f64) (result i32) 642 (local $base i32) 643 (local.set $base (i32.const 8)) 644 (i32.store8 offset=0 (local.get $base) (local.get 0)) 645 (i32.store16 offset=2 (local.get $base) (local.get 1)) 646 (f32.store offset=4 (local.get $base) (local.get 2)) 647 (f64.store offset=8 (local.get $base) (local.get 3)) 648 local.get $base 649 ) 650 651 (func (export "invalid") (result i32) 652 i32.const -8 653 ) 654 ) 655 (core instance $i (instantiate $m)) 656 657 (type $result (tuple s8 u16 float32 float64)) 658 (func (export "tuple") 659 (param s8) (param u16) (param float32) (param float64) (result $result) 660 (canon lift (core func $i "foo") (memory $i "memory")) 661 ) 662 (func (export "invalid") (result $result) 663 (canon lift (core func $i "invalid") (memory $i "memory")) 664 ) 665 ) 666 "#; 667 668 let engine = super::engine(); 669 let component = Component::new(&engine, component)?; 670 let mut store = Store::new(&engine, ()); 671 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 672 673 let input = (-1, 100, 3.0, 100.0); 674 let output = instance 675 .get_typed_func::<(i8, u16, f32, f64), (i8, u16, f32, f64), _>(&mut store, "tuple")? 676 .call_and_post_return(&mut store, input)?; 677 assert_eq!(input, output); 678 679 let invalid_func = 680 instance.get_typed_func::<(), (i8, u16, f32, f64), _>(&mut store, "invalid")?; 681 let err = invalid_func.call(&mut store, ()).err().unwrap(); 682 assert!( 683 err.to_string().contains("pointer out of bounds of memory"), 684 "{}", 685 err 686 ); 687 688 Ok(()) 689 } 690 691 #[test] 692 fn strings() -> Result<()> { 693 let component = format!( 694 r#"(component 695 (core module $m 696 (memory (export "memory") 1) 697 (func (export "roundtrip") (param i32 i32) (result i32) 698 (local $base i32) 699 (local.set $base 700 (call $realloc 701 (i32.const 0) 702 (i32.const 0) 703 (i32.const 4) 704 (i32.const 8))) 705 (i32.store offset=0 706 (local.get $base) 707 (local.get 0)) 708 (i32.store offset=4 709 (local.get $base) 710 (local.get 1)) 711 (local.get $base) 712 ) 713 714 {REALLOC_AND_FREE} 715 ) 716 (core instance $i (instantiate $m)) 717 718 (func (export "list8-to-str") (param (list u8)) (result string) 719 (canon lift 720 (core func $i "roundtrip") 721 (memory $i "memory") 722 (realloc (func $i "realloc")) 723 ) 724 ) 725 (func (export "str-to-list8") (param string) (result (list u8)) 726 (canon lift 727 (core func $i "roundtrip") 728 (memory $i "memory") 729 (realloc (func $i "realloc")) 730 ) 731 ) 732 (func (export "list16-to-str") (param (list u16)) (result string) 733 (canon lift 734 (core func $i "roundtrip") 735 string-encoding=utf16 736 (memory $i "memory") 737 (realloc (func $i "realloc")) 738 ) 739 ) 740 (func (export "str-to-list16") (param string) (result (list u16)) 741 (canon lift 742 (core func $i "roundtrip") 743 string-encoding=utf16 744 (memory $i "memory") 745 (realloc (func $i "realloc")) 746 ) 747 ) 748 )"# 749 ); 750 751 let engine = super::engine(); 752 let component = Component::new(&engine, component)?; 753 let mut store = Store::new(&engine, ()); 754 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 755 let list8_to_str = 756 instance.get_typed_func::<(&[u8],), WasmStr, _>(&mut store, "list8-to-str")?; 757 let str_to_list8 = 758 instance.get_typed_func::<(&str,), WasmList<u8>, _>(&mut store, "str-to-list8")?; 759 let list16_to_str = 760 instance.get_typed_func::<(&[u16],), WasmStr, _>(&mut store, "list16-to-str")?; 761 let str_to_list16 = 762 instance.get_typed_func::<(&str,), WasmList<u16>, _>(&mut store, "str-to-list16")?; 763 764 let mut roundtrip = |x: &str| -> Result<()> { 765 let ret = list8_to_str.call(&mut store, (x.as_bytes(),))?; 766 assert_eq!(ret.to_str(&store)?, x); 767 list8_to_str.post_return(&mut store)?; 768 769 let utf16 = x.encode_utf16().collect::<Vec<_>>(); 770 let ret = list16_to_str.call(&mut store, (&utf16[..],))?; 771 assert_eq!(ret.to_str(&store)?, x); 772 list16_to_str.post_return(&mut store)?; 773 774 let ret = str_to_list8.call(&mut store, (x,))?; 775 assert_eq!(ret.iter(&store).collect::<Result<Vec<_>>>()?, x.as_bytes()); 776 str_to_list8.post_return(&mut store)?; 777 778 let ret = str_to_list16.call(&mut store, (x,))?; 779 assert_eq!(ret.iter(&store).collect::<Result<Vec<_>>>()?, utf16,); 780 str_to_list16.post_return(&mut store)?; 781 782 Ok(()) 783 }; 784 785 roundtrip("")?; 786 roundtrip("foo")?; 787 roundtrip("hello there")?; 788 roundtrip("")?; 789 roundtrip("Löwe 老虎 Léopard")?; 790 791 let ret = list8_to_str.call(&mut store, (b"\xff",))?; 792 let err = ret.to_str(&store).unwrap_err(); 793 assert!(err.to_string().contains("invalid utf-8"), "{}", err); 794 list8_to_str.post_return(&mut store)?; 795 796 let ret = list8_to_str.call(&mut store, (b"hello there \xff invalid",))?; 797 let err = ret.to_str(&store).unwrap_err(); 798 assert!(err.to_string().contains("invalid utf-8"), "{}", err); 799 list8_to_str.post_return(&mut store)?; 800 801 let ret = list16_to_str.call(&mut store, (&[0xd800],))?; 802 let err = ret.to_str(&store).unwrap_err(); 803 assert!(err.to_string().contains("unpaired surrogate"), "{}", err); 804 list16_to_str.post_return(&mut store)?; 805 806 let ret = list16_to_str.call(&mut store, (&[0xdfff],))?; 807 let err = ret.to_str(&store).unwrap_err(); 808 assert!(err.to_string().contains("unpaired surrogate"), "{}", err); 809 list16_to_str.post_return(&mut store)?; 810 811 let ret = list16_to_str.call(&mut store, (&[0xd800, 0xff00],))?; 812 let err = ret.to_str(&store).unwrap_err(); 813 assert!(err.to_string().contains("unpaired surrogate"), "{}", err); 814 list16_to_str.post_return(&mut store)?; 815 816 Ok(()) 817 } 818 819 #[test] 820 fn many_parameters() -> Result<()> { 821 let component = format!( 822 r#"(component 823 (core module $m 824 (memory (export "memory") 1) 825 (func (export "foo") (param i32) (result i32) 826 (local $base i32) 827 828 ;; Allocate space for the return 829 (local.set $base 830 (call $realloc 831 (i32.const 0) 832 (i32.const 0) 833 (i32.const 4) 834 (i32.const 12))) 835 836 ;; Store the pointer/length of the entire linear memory 837 ;; so we have access to everything. 838 (i32.store offset=0 839 (local.get $base) 840 (i32.const 0)) 841 (i32.store offset=4 842 (local.get $base) 843 (i32.mul 844 (memory.size) 845 (i32.const 65536))) 846 847 ;; And also store our pointer parameter 848 (i32.store offset=8 849 (local.get $base) 850 (local.get 0)) 851 852 (local.get $base) 853 ) 854 855 {REALLOC_AND_FREE} 856 ) 857 (core instance $i (instantiate $m)) 858 859 (type $result (tuple (list u8) u32)) 860 (type $t (func 861 (param s8) ;; offset 0, size 1 862 (param u64) ;; offset 8, size 8 863 (param float32) ;; offset 16, size 4 864 (param u8) ;; offset 20, size 1 865 (param unit) ;; offset 21, size 0 866 (param s16) ;; offset 22, size 2 867 (param string) ;; offset 24, size 8 868 (param (list u32)) ;; offset 32, size 8 869 (param bool) ;; offset 40, size 1 870 (param bool) ;; offset 41, size 1 871 (param char) ;; offset 44, size 4 872 (param (list bool)) ;; offset 48, size 8 873 (param (list char)) ;; offset 56, size 8 874 (param (list string)) ;; offset 64, size 8 875 876 (result $result) 877 )) 878 (func (export "many-param") (type $t) 879 (canon lift 880 (core func $i "foo") 881 (memory $i "memory") 882 (realloc (func $i "realloc")) 883 ) 884 ) 885 )"# 886 ); 887 888 let engine = super::engine(); 889 let component = Component::new(&engine, component)?; 890 let mut store = Store::new(&engine, ()); 891 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 892 let func = instance.get_typed_func::<( 893 i8, 894 u64, 895 f32, 896 u8, 897 (), 898 i16, 899 &str, 900 &[u32], 901 bool, 902 bool, 903 char, 904 &[bool], 905 &[char], 906 &[&str], 907 ), (WasmList<u8>, u32), _>(&mut store, "many-param")?; 908 909 let input = ( 910 -100, 911 u64::MAX / 2, 912 f32::from_bits(CANON_32BIT_NAN | 1), 913 38, 914 (), 915 18831, 916 "this is the first string", 917 [1, 2, 3, 4, 5, 6, 7, 8].as_slice(), 918 true, 919 false, 920 '', 921 [false, true, false, true, true].as_slice(), 922 ['', '', '', '', ''].as_slice(), 923 [ 924 "the quick", 925 "brown fox", 926 "was too lazy", 927 "to jump over the dog", 928 "what a demanding dog", 929 ] 930 .as_slice(), 931 ); 932 let (memory, pointer) = func.call(&mut store, input)?; 933 let memory = memory.as_le_slice(&store); 934 935 let mut actual = &memory[pointer as usize..][..72]; 936 assert_eq!(i8::from_le_bytes(*actual.take_n::<1>()), input.0); 937 actual.skip::<7>(); 938 assert_eq!(u64::from_le_bytes(*actual.take_n::<8>()), input.1); 939 assert_eq!(u32::from_le_bytes(*actual.take_n::<4>()), CANON_32BIT_NAN); 940 assert_eq!(u8::from_le_bytes(*actual.take_n::<1>()), input.3); 941 actual.skip::<1>(); 942 assert_eq!(i16::from_le_bytes(*actual.take_n::<2>()), input.5); 943 assert_eq!(actual.ptr_len(memory, 1), input.6.as_bytes()); 944 let mut mem = actual.ptr_len(memory, 4); 945 for expected in input.7.iter() { 946 assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected); 947 } 948 assert!(mem.is_empty()); 949 assert_eq!(actual.take_n::<1>(), &[input.8 as u8]); 950 assert_eq!(actual.take_n::<1>(), &[input.9 as u8]); 951 actual.skip::<2>(); 952 assert_eq!(u32::from_le_bytes(*actual.take_n::<4>()), input.10 as u32); 953 954 // (list bool) 955 mem = actual.ptr_len(memory, 1); 956 for expected in input.11.iter() { 957 assert_eq!(mem.take_n::<1>(), &[*expected as u8]); 958 } 959 assert!(mem.is_empty()); 960 961 // (list char) 962 mem = actual.ptr_len(memory, 4); 963 for expected in input.12.iter() { 964 assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected as u32); 965 } 966 assert!(mem.is_empty()); 967 968 // (list string) 969 mem = actual.ptr_len(memory, 8); 970 for expected in input.13.iter() { 971 let actual = mem.ptr_len(memory, 1); 972 assert_eq!(actual, expected.as_bytes()); 973 } 974 assert!(mem.is_empty()); 975 assert!(actual.is_empty()); 976 977 Ok(()) 978 } 979 980 #[test] 981 fn some_traps() -> Result<()> { 982 let middle_of_memory = (i32::MAX / 2) & (!0xff); 983 let component = format!( 984 r#"(component 985 (core module $m 986 (memory (export "memory") 1) 987 (func (export "take-many") (param i32)) 988 (func (export "take-list") (param i32 i32)) 989 990 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 991 unreachable) 992 ) 993 (core instance $i (instantiate $m)) 994 995 (func (export "take-list-unreachable") (param (list u8)) 996 (canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc"))) 997 ) 998 (func (export "take-string-unreachable") (param string) 999 (canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc"))) 1000 ) 1001 1002 (type $t (func 1003 (param string) 1004 (param string) 1005 (param string) 1006 (param string) 1007 (param string) 1008 (param string) 1009 (param string) 1010 (param string) 1011 (param string) 1012 (param string) 1013 )) 1014 (func (export "take-many-unreachable") (type $t) 1015 (canon lift (core func $i "take-many") (memory $i "memory") (realloc (func $i "realloc"))) 1016 ) 1017 1018 (core module $m2 1019 (memory (export "memory") 1) 1020 (func (export "take-many") (param i32)) 1021 (func (export "take-list") (param i32 i32)) 1022 1023 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 1024 i32.const {middle_of_memory}) 1025 ) 1026 (core instance $i2 (instantiate $m2)) 1027 1028 (func (export "take-list-base-oob") (param (list u8)) 1029 (canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc"))) 1030 ) 1031 (func (export "take-string-base-oob") (param string) 1032 (canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc"))) 1033 ) 1034 (func (export "take-many-base-oob") (type $t) 1035 (canon lift (core func $i2 "take-many") (memory $i2 "memory") (realloc (func $i2 "realloc"))) 1036 ) 1037 1038 (core module $m3 1039 (memory (export "memory") 1) 1040 (func (export "take-many") (param i32)) 1041 (func (export "take-list") (param i32 i32)) 1042 1043 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 1044 i32.const 65532) 1045 ) 1046 (core instance $i3 (instantiate $m3)) 1047 1048 (func (export "take-list-end-oob") (param (list u8)) 1049 (canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc"))) 1050 ) 1051 (func (export "take-string-end-oob") (param string) 1052 (canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc"))) 1053 ) 1054 (func (export "take-many-end-oob") (type $t) 1055 (canon lift (core func $i3 "take-many") (memory $i3 "memory") (realloc (func $i3 "realloc"))) 1056 ) 1057 1058 (core module $m4 1059 (memory (export "memory") 1) 1060 (func (export "take-many") (param i32)) 1061 1062 (global $cnt (mut i32) (i32.const 0)) 1063 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 1064 global.get $cnt 1065 if (result i32) 1066 i32.const 100000 1067 else 1068 i32.const 1 1069 global.set $cnt 1070 i32.const 0 1071 end 1072 ) 1073 ) 1074 (core instance $i4 (instantiate $m4)) 1075 1076 (func (export "take-many-second-oob") (type $t) 1077 (canon lift (core func $i4 "take-many") (memory $i4 "memory") (realloc (func $i4 "realloc"))) 1078 ) 1079 )"# 1080 ); 1081 1082 let engine = super::engine(); 1083 let component = Component::new(&engine, component)?; 1084 let mut store = Store::new(&engine, ()); 1085 let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component); 1086 1087 // This should fail when calling the allocator function for the argument 1088 let err = instance(&mut store)? 1089 .get_typed_func::<(&[u8],), (), _>(&mut store, "take-list-unreachable")? 1090 .call(&mut store, (&[],)) 1091 .unwrap_err() 1092 .downcast::<Trap>()?; 1093 assert_eq!(err.trap_code(), Some(TrapCode::UnreachableCodeReached)); 1094 1095 // This should fail when calling the allocator function for the argument 1096 let err = instance(&mut store)? 1097 .get_typed_func::<(&str,), (), _>(&mut store, "take-string-unreachable")? 1098 .call(&mut store, ("",)) 1099 .unwrap_err() 1100 .downcast::<Trap>()?; 1101 assert_eq!(err.trap_code(), Some(TrapCode::UnreachableCodeReached)); 1102 1103 // This should fail when calling the allocator function for the space 1104 // to store the arguments (before arguments are even lowered) 1105 let err = instance(&mut store)? 1106 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), (), _>( 1107 &mut store, 1108 "take-many-unreachable", 1109 )? 1110 .call(&mut store, ("", "", "", "", "", "", "", "", "", "")) 1111 .unwrap_err() 1112 .downcast::<Trap>()?; 1113 assert_eq!(err.trap_code(), Some(TrapCode::UnreachableCodeReached)); 1114 1115 // Assert that when the base pointer returned by malloc is out of bounds 1116 // that errors are reported as such. Both empty and lists with contents 1117 // should all be invalid here. 1118 // 1119 // FIXME(WebAssembly/component-model#32) confirm the semantics here are 1120 // what's desired. 1121 #[track_caller] 1122 fn assert_oob(err: &anyhow::Error) { 1123 assert!( 1124 err.to_string() 1125 .contains("realloc return: beyond end of memory"), 1126 "{:?}", 1127 err, 1128 ); 1129 } 1130 let err = instance(&mut store)? 1131 .get_typed_func::<(&[u8],), (), _>(&mut store, "take-list-base-oob")? 1132 .call(&mut store, (&[],)) 1133 .unwrap_err(); 1134 assert_oob(&err); 1135 let err = instance(&mut store)? 1136 .get_typed_func::<(&[u8],), (), _>(&mut store, "take-list-base-oob")? 1137 .call(&mut store, (&[1],)) 1138 .unwrap_err(); 1139 assert_oob(&err); 1140 let err = instance(&mut store)? 1141 .get_typed_func::<(&str,), (), _>(&mut store, "take-string-base-oob")? 1142 .call(&mut store, ("",)) 1143 .unwrap_err(); 1144 assert_oob(&err); 1145 let err = instance(&mut store)? 1146 .get_typed_func::<(&str,), (), _>(&mut store, "take-string-base-oob")? 1147 .call(&mut store, ("x",)) 1148 .unwrap_err(); 1149 assert_oob(&err); 1150 let err = instance(&mut store)? 1151 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), (), _>( 1152 &mut store, 1153 "take-many-base-oob", 1154 )? 1155 .call(&mut store, ("", "", "", "", "", "", "", "", "", "")) 1156 .unwrap_err(); 1157 assert_oob(&err); 1158 1159 // Test here that when the returned pointer from malloc is one byte from the 1160 // end of memory that empty things are fine, but larger things are not. 1161 1162 instance(&mut store)? 1163 .get_typed_func::<(&[u8],), (), _>(&mut store, "take-list-end-oob")? 1164 .call_and_post_return(&mut store, (&[],))?; 1165 instance(&mut store)? 1166 .get_typed_func::<(&[u8],), (), _>(&mut store, "take-list-end-oob")? 1167 .call_and_post_return(&mut store, (&[1, 2, 3, 4],))?; 1168 let err = instance(&mut store)? 1169 .get_typed_func::<(&[u8],), (), _>(&mut store, "take-list-end-oob")? 1170 .call(&mut store, (&[1, 2, 3, 4, 5],)) 1171 .unwrap_err(); 1172 assert_oob(&err); 1173 instance(&mut store)? 1174 .get_typed_func::<(&str,), (), _>(&mut store, "take-string-end-oob")? 1175 .call_and_post_return(&mut store, ("",))?; 1176 instance(&mut store)? 1177 .get_typed_func::<(&str,), (), _>(&mut store, "take-string-end-oob")? 1178 .call_and_post_return(&mut store, ("abcd",))?; 1179 let err = instance(&mut store)? 1180 .get_typed_func::<(&str,), (), _>(&mut store, "take-string-end-oob")? 1181 .call(&mut store, ("abcde",)) 1182 .unwrap_err(); 1183 assert_oob(&err); 1184 let err = instance(&mut store)? 1185 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), (), _>( 1186 &mut store, 1187 "take-many-end-oob", 1188 )? 1189 .call(&mut store, ("", "", "", "", "", "", "", "", "", "")) 1190 .unwrap_err(); 1191 assert_oob(&err); 1192 1193 // For this function the first allocation, the space to store all the 1194 // arguments, is in-bounds but then all further allocations, such as for 1195 // each individual string, are all out of bounds. 1196 let err = instance(&mut store)? 1197 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), (), _>( 1198 &mut store, 1199 "take-many-second-oob", 1200 )? 1201 .call(&mut store, ("", "", "", "", "", "", "", "", "", "")) 1202 .unwrap_err(); 1203 assert_oob(&err); 1204 let err = instance(&mut store)? 1205 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), (), _>( 1206 &mut store, 1207 "take-many-second-oob", 1208 )? 1209 .call(&mut store, ("", "", "", "", "", "", "", "", "", "x")) 1210 .unwrap_err(); 1211 assert_oob(&err); 1212 Ok(()) 1213 } 1214 1215 #[test] 1216 fn char_bool_memory() -> Result<()> { 1217 let component = format!( 1218 r#"(component 1219 (core module $m 1220 (memory (export "memory") 1) 1221 (func (export "ret-tuple") (param i32 i32) (result i32) 1222 (local $base i32) 1223 1224 ;; Allocate space for the return 1225 (local.set $base 1226 (call $realloc 1227 (i32.const 0) 1228 (i32.const 0) 1229 (i32.const 4) 1230 (i32.const 8))) 1231 1232 ;; store the boolean 1233 (i32.store offset=0 1234 (local.get $base) 1235 (local.get 0)) 1236 1237 ;; store the char 1238 (i32.store offset=4 1239 (local.get $base) 1240 (local.get 1)) 1241 1242 (local.get $base) 1243 ) 1244 1245 {REALLOC_AND_FREE} 1246 ) 1247 (core instance $i (instantiate $m)) 1248 1249 (func (export "ret-tuple") (param u32) (param u32) (result (tuple bool char)) 1250 (canon lift (core func $i "ret-tuple") 1251 (memory $i "memory") 1252 (realloc (func $i "realloc"))) 1253 ) 1254 )"# 1255 ); 1256 1257 let engine = super::engine(); 1258 let component = Component::new(&engine, component)?; 1259 let mut store = Store::new(&engine, ()); 1260 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 1261 let func = instance.get_typed_func::<(u32, u32), (bool, char), _>(&mut store, "ret-tuple")?; 1262 1263 let ret = func.call(&mut store, (0, 'a' as u32))?; 1264 assert_eq!(ret, (false, 'a')); 1265 func.post_return(&mut store)?; 1266 1267 let ret = func.call(&mut store, (1, '' as u32))?; 1268 assert_eq!(ret, (true, '')); 1269 func.post_return(&mut store)?; 1270 1271 let ret = func.call(&mut store, (2, 'a' as u32))?; 1272 assert_eq!(ret, (true, 'a')); 1273 func.post_return(&mut store)?; 1274 1275 assert!(func.call(&mut store, (0, 0xd800)).is_err()); 1276 1277 Ok(()) 1278 } 1279 1280 #[test] 1281 fn string_list_oob() -> Result<()> { 1282 let component = format!( 1283 r#"(component 1284 (core module $m 1285 (memory (export "memory") 1) 1286 (func (export "ret-list") (result i32) 1287 (local $base i32) 1288 1289 ;; Allocate space for the return 1290 (local.set $base 1291 (call $realloc 1292 (i32.const 0) 1293 (i32.const 0) 1294 (i32.const 4) 1295 (i32.const 8))) 1296 1297 (i32.store offset=0 1298 (local.get $base) 1299 (i32.const 100000)) 1300 (i32.store offset=4 1301 (local.get $base) 1302 (i32.const 1)) 1303 1304 (local.get $base) 1305 ) 1306 1307 {REALLOC_AND_FREE} 1308 ) 1309 (core instance $i (instantiate $m)) 1310 1311 (func (export "ret-list-u8") (result (list u8)) 1312 (canon lift (core func $i "ret-list") 1313 (memory $i "memory") 1314 (realloc (func $i "realloc")) 1315 ) 1316 ) 1317 (func (export "ret-string") (result string) 1318 (canon lift (core func $i "ret-list") 1319 (memory $i "memory") 1320 (realloc (func $i "realloc")) 1321 ) 1322 ) 1323 )"# 1324 ); 1325 1326 let engine = super::engine(); 1327 let component = Component::new(&engine, component)?; 1328 let mut store = Store::new(&engine, ()); 1329 let ret_list_u8 = Linker::new(&engine) 1330 .instantiate(&mut store, &component)? 1331 .get_typed_func::<(), WasmList<u8>, _>(&mut store, "ret-list-u8")?; 1332 let ret_string = Linker::new(&engine) 1333 .instantiate(&mut store, &component)? 1334 .get_typed_func::<(), WasmStr, _>(&mut store, "ret-string")?; 1335 1336 let err = ret_list_u8.call(&mut store, ()).err().unwrap(); 1337 assert!(err.to_string().contains("out of bounds"), "{}", err); 1338 1339 let err = ret_string.call(&mut store, ()).err().unwrap(); 1340 assert!(err.to_string().contains("out of bounds"), "{}", err); 1341 1342 Ok(()) 1343 } 1344 1345 #[test] 1346 fn tuples() -> Result<()> { 1347 let component = format!( 1348 r#"(component 1349 (core module $m 1350 (memory (export "memory") 1) 1351 (func (export "foo") 1352 (param i32 f64 i32) 1353 (result i32) 1354 1355 local.get 0 1356 i32.const 0 1357 i32.ne 1358 if unreachable end 1359 1360 local.get 1 1361 f64.const 1 1362 f64.ne 1363 if unreachable end 1364 1365 local.get 2 1366 i32.const 2 1367 i32.ne 1368 if unreachable end 1369 1370 i32.const 3 1371 ) 1372 ) 1373 (core instance $i (instantiate $m)) 1374 1375 (func (export "foo") 1376 (param (tuple s32 float64)) 1377 (param (tuple s8)) 1378 (result (tuple u16)) 1379 (canon lift (core func $i "foo")) 1380 ) 1381 )"# 1382 ); 1383 1384 let engine = super::engine(); 1385 let component = Component::new(&engine, component)?; 1386 let mut store = Store::new(&engine, ()); 1387 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 1388 let foo = instance.get_typed_func::<((i32, f64), (i8,)), (u16,), _>(&mut store, "foo")?; 1389 assert_eq!(foo.call(&mut store, ((0, 1.0), (2,)))?, (3,)); 1390 1391 Ok(()) 1392 } 1393 1394 #[test] 1395 fn option() -> Result<()> { 1396 let component = format!( 1397 r#"(component 1398 (core module $m 1399 (memory (export "memory") 1) 1400 (func (export "pass0") (param i32) (result i32) 1401 local.get 0 1402 ) 1403 (func (export "pass1") (param i32 i32) (result i32) 1404 (local $base i32) 1405 (local.set $base 1406 (call $realloc 1407 (i32.const 0) 1408 (i32.const 0) 1409 (i32.const 4) 1410 (i32.const 8))) 1411 1412 (i32.store offset=0 1413 (local.get $base) 1414 (local.get 0)) 1415 (i32.store offset=4 1416 (local.get $base) 1417 (local.get 1)) 1418 1419 (local.get $base) 1420 ) 1421 (func (export "pass2") (param i32 i32 i32) (result i32) 1422 (local $base i32) 1423 (local.set $base 1424 (call $realloc 1425 (i32.const 0) 1426 (i32.const 0) 1427 (i32.const 4) 1428 (i32.const 12))) 1429 1430 (i32.store offset=0 1431 (local.get $base) 1432 (local.get 0)) 1433 (i32.store offset=4 1434 (local.get $base) 1435 (local.get 1)) 1436 (i32.store offset=8 1437 (local.get $base) 1438 (local.get 2)) 1439 1440 (local.get $base) 1441 ) 1442 1443 {REALLOC_AND_FREE} 1444 ) 1445 (core instance $i (instantiate $m)) 1446 1447 (func (export "option-unit-to-u32") (param (option unit)) (result u32) 1448 (canon lift (core func $i "pass0")) 1449 ) 1450 (func (export "option-u8-to-tuple") (param (option u8)) (result (tuple u32 u32)) 1451 (canon lift (core func $i "pass1") (memory $i "memory")) 1452 ) 1453 (func (export "option-u32-to-tuple") (param (option u32)) (result (tuple u32 u32)) 1454 (canon lift (core func $i "pass1") (memory $i "memory")) 1455 ) 1456 (func (export "option-string-to-tuple") (param (option string)) (result (tuple u32 string)) 1457 (canon lift 1458 (core func $i "pass2") 1459 (memory $i "memory") 1460 (realloc (func $i "realloc")) 1461 ) 1462 ) 1463 (func (export "to-option-unit") (param u32) (result (option unit)) 1464 (canon lift (core func $i "pass0")) 1465 ) 1466 (func (export "to-option-u8") (param u32) (param u32) (result (option u8)) 1467 (canon lift (core func $i "pass1") (memory $i "memory")) 1468 ) 1469 (func (export "to-option-u32") (param u32) (param u32) (result (option u32)) 1470 (canon lift 1471 (core func $i "pass1") 1472 (memory $i "memory") 1473 ) 1474 ) 1475 (func (export "to-option-string") (param u32) (param string) (result (option string)) 1476 (canon lift 1477 (core func $i "pass2") 1478 (memory $i "memory") 1479 (realloc (func $i "realloc")) 1480 ) 1481 ) 1482 )"# 1483 ); 1484 1485 let engine = super::engine(); 1486 let component = Component::new(&engine, component)?; 1487 let mut store = Store::new(&engine, ()); 1488 let linker = Linker::new(&engine); 1489 let instance = linker.instantiate(&mut store, &component)?; 1490 let option_unit_to_u32 = 1491 instance.get_typed_func::<(Option<()>,), u32, _>(&mut store, "option-unit-to-u32")?; 1492 assert_eq!(option_unit_to_u32.call(&mut store, (None,))?, 0); 1493 option_unit_to_u32.post_return(&mut store)?; 1494 assert_eq!(option_unit_to_u32.call(&mut store, (Some(()),))?, 1); 1495 option_unit_to_u32.post_return(&mut store)?; 1496 1497 let option_u8_to_tuple = instance 1498 .get_typed_func::<(Option<u8>,), (u32, u32), _>(&mut store, "option-u8-to-tuple")?; 1499 assert_eq!(option_u8_to_tuple.call(&mut store, (None,))?, (0, 0)); 1500 option_u8_to_tuple.post_return(&mut store)?; 1501 assert_eq!(option_u8_to_tuple.call(&mut store, (Some(0),))?, (1, 0)); 1502 option_u8_to_tuple.post_return(&mut store)?; 1503 assert_eq!(option_u8_to_tuple.call(&mut store, (Some(100),))?, (1, 100)); 1504 option_u8_to_tuple.post_return(&mut store)?; 1505 1506 let option_u32_to_tuple = instance 1507 .get_typed_func::<(Option<u32>,), (u32, u32), _>(&mut store, "option-u32-to-tuple")?; 1508 assert_eq!(option_u32_to_tuple.call(&mut store, (None,))?, (0, 0)); 1509 option_u32_to_tuple.post_return(&mut store)?; 1510 assert_eq!(option_u32_to_tuple.call(&mut store, (Some(0),))?, (1, 0)); 1511 option_u32_to_tuple.post_return(&mut store)?; 1512 assert_eq!( 1513 option_u32_to_tuple.call(&mut store, (Some(100),))?, 1514 (1, 100) 1515 ); 1516 option_u32_to_tuple.post_return(&mut store)?; 1517 1518 let option_string_to_tuple = instance.get_typed_func::<(Option<&str>,), (u32, WasmStr), _>( 1519 &mut store, 1520 "option-string-to-tuple", 1521 )?; 1522 let (a, b) = option_string_to_tuple.call(&mut store, (None,))?; 1523 assert_eq!(a, 0); 1524 assert_eq!(b.to_str(&store)?, ""); 1525 option_string_to_tuple.post_return(&mut store)?; 1526 let (a, b) = option_string_to_tuple.call(&mut store, (Some(""),))?; 1527 assert_eq!(a, 1); 1528 assert_eq!(b.to_str(&store)?, ""); 1529 option_string_to_tuple.post_return(&mut store)?; 1530 let (a, b) = option_string_to_tuple.call(&mut store, (Some("hello"),))?; 1531 assert_eq!(a, 1); 1532 assert_eq!(b.to_str(&store)?, "hello"); 1533 option_string_to_tuple.post_return(&mut store)?; 1534 1535 let instance = linker.instantiate(&mut store, &component)?; 1536 let to_option_unit = 1537 instance.get_typed_func::<(u32,), Option<()>, _>(&mut store, "to-option-unit")?; 1538 assert_eq!(to_option_unit.call(&mut store, (0,))?, None); 1539 to_option_unit.post_return(&mut store)?; 1540 assert_eq!(to_option_unit.call(&mut store, (1,))?, Some(())); 1541 to_option_unit.post_return(&mut store)?; 1542 let err = to_option_unit.call(&mut store, (2,)).unwrap_err(); 1543 assert!(err.to_string().contains("invalid option"), "{}", err); 1544 1545 let instance = linker.instantiate(&mut store, &component)?; 1546 let to_option_u8 = 1547 instance.get_typed_func::<(u32, u32), Option<u8>, _>(&mut store, "to-option-u8")?; 1548 assert_eq!(to_option_u8.call(&mut store, (0x00_00, 0))?, None); 1549 to_option_u8.post_return(&mut store)?; 1550 assert_eq!(to_option_u8.call(&mut store, (0x00_01, 0))?, Some(0)); 1551 to_option_u8.post_return(&mut store)?; 1552 assert_eq!(to_option_u8.call(&mut store, (0xfd_01, 0))?, Some(0xfd)); 1553 to_option_u8.post_return(&mut store)?; 1554 assert!(to_option_u8.call(&mut store, (0x00_02, 0)).is_err()); 1555 1556 let instance = linker.instantiate(&mut store, &component)?; 1557 let to_option_u32 = 1558 instance.get_typed_func::<(u32, u32), Option<u32>, _>(&mut store, "to-option-u32")?; 1559 assert_eq!(to_option_u32.call(&mut store, (0, 0))?, None); 1560 to_option_u32.post_return(&mut store)?; 1561 assert_eq!(to_option_u32.call(&mut store, (1, 0))?, Some(0)); 1562 to_option_u32.post_return(&mut store)?; 1563 assert_eq!( 1564 to_option_u32.call(&mut store, (1, 0x1234fead))?, 1565 Some(0x1234fead) 1566 ); 1567 to_option_u32.post_return(&mut store)?; 1568 assert!(to_option_u32.call(&mut store, (2, 0)).is_err()); 1569 1570 let instance = linker.instantiate(&mut store, &component)?; 1571 let to_option_string = instance 1572 .get_typed_func::<(u32, &str), Option<WasmStr>, _>(&mut store, "to-option-string")?; 1573 let ret = to_option_string.call(&mut store, (0, ""))?; 1574 assert!(ret.is_none()); 1575 to_option_string.post_return(&mut store)?; 1576 let ret = to_option_string.call(&mut store, (1, ""))?; 1577 assert_eq!(ret.unwrap().to_str(&store)?, ""); 1578 to_option_string.post_return(&mut store)?; 1579 let ret = to_option_string.call(&mut store, (1, "cheesecake"))?; 1580 assert_eq!(ret.unwrap().to_str(&store)?, "cheesecake"); 1581 to_option_string.post_return(&mut store)?; 1582 assert!(to_option_string.call(&mut store, (2, "")).is_err()); 1583 1584 Ok(()) 1585 } 1586 1587 #[test] 1588 fn expected() -> Result<()> { 1589 let component = format!( 1590 r#"(component 1591 (core module $m 1592 (memory (export "memory") 1) 1593 (func (export "pass0") (param i32) (result i32) 1594 local.get 0 1595 ) 1596 (func (export "pass1") (param i32 i32) (result i32) 1597 (local $base i32) 1598 (local.set $base 1599 (call $realloc 1600 (i32.const 0) 1601 (i32.const 0) 1602 (i32.const 4) 1603 (i32.const 8))) 1604 1605 (i32.store offset=0 1606 (local.get $base) 1607 (local.get 0)) 1608 (i32.store offset=4 1609 (local.get $base) 1610 (local.get 1)) 1611 1612 (local.get $base) 1613 ) 1614 (func (export "pass2") (param i32 i32 i32) (result i32) 1615 (local $base i32) 1616 (local.set $base 1617 (call $realloc 1618 (i32.const 0) 1619 (i32.const 0) 1620 (i32.const 4) 1621 (i32.const 12))) 1622 1623 (i32.store offset=0 1624 (local.get $base) 1625 (local.get 0)) 1626 (i32.store offset=4 1627 (local.get $base) 1628 (local.get 1)) 1629 (i32.store offset=8 1630 (local.get $base) 1631 (local.get 2)) 1632 1633 (local.get $base) 1634 ) 1635 1636 {REALLOC_AND_FREE} 1637 ) 1638 (core instance $i (instantiate $m)) 1639 1640 (func (export "take-expected-unit") (param (expected unit unit)) (result u32) 1641 (canon lift (core func $i "pass0")) 1642 ) 1643 (func (export "take-expected-u8-f32") (param (expected u8 float32)) (result (tuple u32 u32)) 1644 (canon lift (core func $i "pass1") (memory $i "memory")) 1645 ) 1646 (type $list (list u8)) 1647 (func (export "take-expected-string") (param (expected string $list)) (result (tuple u32 string)) 1648 (canon lift 1649 (core func $i "pass2") 1650 (memory $i "memory") 1651 (realloc (func $i "realloc")) 1652 ) 1653 ) 1654 (func (export "to-expected-unit") (param u32) (result (expected unit unit)) 1655 (canon lift (core func $i "pass0")) 1656 ) 1657 (func (export "to-expected-s16-f32") (param u32) (param u32) (result (expected s16 float32)) 1658 (canon lift 1659 (core func $i "pass1") 1660 (memory $i "memory") 1661 (realloc (func $i "realloc")) 1662 ) 1663 ) 1664 )"# 1665 ); 1666 1667 let engine = super::engine(); 1668 let component = Component::new(&engine, component)?; 1669 let mut store = Store::new(&engine, ()); 1670 let linker = Linker::new(&engine); 1671 let instance = linker.instantiate(&mut store, &component)?; 1672 let take_expected_unit = 1673 instance.get_typed_func::<(Result<(), ()>,), u32, _>(&mut store, "take-expected-unit")?; 1674 assert_eq!(take_expected_unit.call(&mut store, (Ok(()),))?, 0); 1675 take_expected_unit.post_return(&mut store)?; 1676 assert_eq!(take_expected_unit.call(&mut store, (Err(()),))?, 1); 1677 take_expected_unit.post_return(&mut store)?; 1678 1679 let take_expected_u8_f32 = instance 1680 .get_typed_func::<(Result<u8, f32>,), (u32, u32), _>(&mut store, "take-expected-u8-f32")?; 1681 assert_eq!(take_expected_u8_f32.call(&mut store, (Ok(1),))?, (0, 1)); 1682 take_expected_u8_f32.post_return(&mut store)?; 1683 assert_eq!( 1684 take_expected_u8_f32.call(&mut store, (Err(2.0),))?, 1685 (1, 2.0f32.to_bits()) 1686 ); 1687 take_expected_u8_f32.post_return(&mut store)?; 1688 1689 let take_expected_string = instance 1690 .get_typed_func::<(Result<&str, &[u8]>,), (u32, WasmStr), _>( 1691 &mut store, 1692 "take-expected-string", 1693 )?; 1694 let (a, b) = take_expected_string.call(&mut store, (Ok("hello"),))?; 1695 assert_eq!(a, 0); 1696 assert_eq!(b.to_str(&store)?, "hello"); 1697 take_expected_string.post_return(&mut store)?; 1698 let (a, b) = take_expected_string.call(&mut store, (Err(b"goodbye"),))?; 1699 assert_eq!(a, 1); 1700 assert_eq!(b.to_str(&store)?, "goodbye"); 1701 take_expected_string.post_return(&mut store)?; 1702 1703 let instance = linker.instantiate(&mut store, &component)?; 1704 let to_expected_unit = 1705 instance.get_typed_func::<(u32,), Result<(), ()>, _>(&mut store, "to-expected-unit")?; 1706 assert_eq!(to_expected_unit.call(&mut store, (0,))?, Ok(())); 1707 to_expected_unit.post_return(&mut store)?; 1708 assert_eq!(to_expected_unit.call(&mut store, (1,))?, Err(())); 1709 to_expected_unit.post_return(&mut store)?; 1710 let err = to_expected_unit.call(&mut store, (2,)).unwrap_err(); 1711 assert!(err.to_string().contains("invalid expected"), "{}", err); 1712 1713 let instance = linker.instantiate(&mut store, &component)?; 1714 let to_expected_s16_f32 = instance 1715 .get_typed_func::<(u32, u32), Result<i16, f32>, _>(&mut store, "to-expected-s16-f32")?; 1716 assert_eq!(to_expected_s16_f32.call(&mut store, (0, 0))?, Ok(0)); 1717 to_expected_s16_f32.post_return(&mut store)?; 1718 assert_eq!(to_expected_s16_f32.call(&mut store, (0, 100))?, Ok(100)); 1719 to_expected_s16_f32.post_return(&mut store)?; 1720 assert_eq!( 1721 to_expected_s16_f32.call(&mut store, (1, 1.0f32.to_bits()))?, 1722 Err(1.0) 1723 ); 1724 to_expected_s16_f32.post_return(&mut store)?; 1725 let ret = to_expected_s16_f32.call(&mut store, (1, CANON_32BIT_NAN | 1))?; 1726 assert_eq!(ret.unwrap_err().to_bits(), CANON_32BIT_NAN); 1727 to_expected_s16_f32.post_return(&mut store)?; 1728 assert!(to_expected_s16_f32.call(&mut store, (2, 0)).is_err()); 1729 1730 Ok(()) 1731 } 1732 1733 #[test] 1734 fn fancy_list() -> Result<()> { 1735 let component = format!( 1736 r#"(component 1737 (core module $m 1738 (memory (export "memory") 1) 1739 (func (export "take") (param i32 i32) (result i32) 1740 (local $base i32) 1741 (local.set $base 1742 (call $realloc 1743 (i32.const 0) 1744 (i32.const 0) 1745 (i32.const 4) 1746 (i32.const 16))) 1747 1748 (i32.store offset=0 1749 (local.get $base) 1750 (local.get 0)) 1751 (i32.store offset=4 1752 (local.get $base) 1753 (local.get 1)) 1754 (i32.store offset=8 1755 (local.get $base) 1756 (i32.const 0)) 1757 (i32.store offset=12 1758 (local.get $base) 1759 (i32.mul 1760 (memory.size) 1761 (i32.const 65536))) 1762 1763 (local.get $base) 1764 ) 1765 1766 {REALLOC_AND_FREE} 1767 ) 1768 (core instance $i (instantiate $m)) 1769 1770 (type $a (option u8)) 1771 (type $b (expected unit string)) 1772 (type $input (list (tuple $a $b))) 1773 (type $output (tuple u32 u32 (list u8))) 1774 (func (export "take") (param $input) (result $output) 1775 (canon lift 1776 (core func $i "take") 1777 (memory $i "memory") 1778 (realloc (func $i "realloc")) 1779 ) 1780 ) 1781 )"# 1782 ); 1783 1784 let engine = super::engine(); 1785 let component = Component::new(&engine, component)?; 1786 let mut store = Store::new(&engine, ()); 1787 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 1788 1789 let func = instance 1790 .get_typed_func::<(&[(Option<u8>, Result<(), &str>)],), (u32, u32, WasmList<u8>), _>( 1791 &mut store, "take", 1792 )?; 1793 1794 let input = [ 1795 (None, Ok(())), 1796 (Some(2), Err("hello there")), 1797 (Some(200), Err("general kenobi")), 1798 ]; 1799 let (ptr, len, list) = func.call(&mut store, (&input,))?; 1800 let memory = list.as_le_slice(&store); 1801 let ptr = usize::try_from(ptr).unwrap(); 1802 let len = usize::try_from(len).unwrap(); 1803 let mut array = &memory[ptr..][..len * 16]; 1804 1805 for (a, b) in input.iter() { 1806 match a { 1807 Some(val) => { 1808 assert_eq!(*array.take_n::<2>(), [1, *val]); 1809 } 1810 None => { 1811 assert_eq!(*array.take_n::<1>(), [0]); 1812 array.skip::<1>(); 1813 } 1814 } 1815 array.skip::<2>(); 1816 match b { 1817 Ok(()) => { 1818 assert_eq!(*array.take_n::<1>(), [0]); 1819 array.skip::<11>(); 1820 } 1821 Err(s) => { 1822 assert_eq!(*array.take_n::<1>(), [1]); 1823 array.skip::<3>(); 1824 assert_eq!(array.ptr_len(memory, 1), s.as_bytes()); 1825 } 1826 } 1827 } 1828 assert!(array.is_empty()); 1829 1830 Ok(()) 1831 } 1832 1833 trait SliceExt<'a> { 1834 fn take_n<const N: usize>(&mut self) -> &'a [u8; N]; 1835 1836 fn skip<const N: usize>(&mut self) { 1837 self.take_n::<N>(); 1838 } 1839 1840 fn ptr_len<'b>(&mut self, all_memory: &'b [u8], size: usize) -> &'b [u8] { 1841 let ptr = u32::from_le_bytes(*self.take_n::<4>()); 1842 let len = u32::from_le_bytes(*self.take_n::<4>()); 1843 let ptr = usize::try_from(ptr).unwrap(); 1844 let len = usize::try_from(len).unwrap(); 1845 &all_memory[ptr..][..len * size] 1846 } 1847 } 1848 1849 impl<'a> SliceExt<'a> for &'a [u8] { 1850 fn take_n<const N: usize>(&mut self) -> &'a [u8; N] { 1851 let (a, b) = self.split_at(N); 1852 *self = b; 1853 a.try_into().unwrap() 1854 } 1855 } 1856 1857 #[test] 1858 fn invalid_alignment() -> Result<()> { 1859 let component = format!( 1860 r#"(component 1861 (core module $m 1862 (memory (export "memory") 1) 1863 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 1864 i32.const 1) 1865 1866 (func (export "take-i32") (param i32)) 1867 (func (export "ret-1") (result i32) i32.const 1) 1868 (func (export "ret-unaligned-list") (result i32) 1869 (i32.store offset=0 (i32.const 8) (i32.const 1)) 1870 (i32.store offset=4 (i32.const 8) (i32.const 1)) 1871 i32.const 8) 1872 ) 1873 (core instance $i (instantiate $m)) 1874 1875 (func (export "many-params") 1876 (param string) (param string) (param string) (param string) 1877 (param string) (param string) (param string) (param string) 1878 (param string) (param string) (param string) (param string) 1879 (canon lift 1880 (core func $i "take-i32") 1881 (memory $i "memory") 1882 (realloc (func $i "realloc")) 1883 ) 1884 ) 1885 (func (export "string-ret") (result string) 1886 (canon lift 1887 (core func $i "ret-1") 1888 (memory $i "memory") 1889 (realloc (func $i "realloc")) 1890 ) 1891 ) 1892 (func (export "list-u32-ret") (result (list u32)) 1893 (canon lift 1894 (core func $i "ret-unaligned-list") 1895 (memory $i "memory") 1896 (realloc (func $i "realloc")) 1897 ) 1898 ) 1899 )"# 1900 ); 1901 1902 let engine = super::engine(); 1903 let component = Component::new(&engine, component)?; 1904 let mut store = Store::new(&engine, ()); 1905 let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component); 1906 1907 let err = instance(&mut store)? 1908 .get_typed_func::<( 1909 &str, 1910 &str, 1911 &str, 1912 &str, 1913 &str, 1914 &str, 1915 &str, 1916 &str, 1917 &str, 1918 &str, 1919 &str, 1920 &str, 1921 ), (), _>(&mut store, "many-params")? 1922 .call(&mut store, ("", "", "", "", "", "", "", "", "", "", "", "")) 1923 .unwrap_err(); 1924 assert!( 1925 err.to_string() 1926 .contains("realloc return: result not aligned"), 1927 "{}", 1928 err 1929 ); 1930 1931 let err = instance(&mut store)? 1932 .get_typed_func::<(), WasmStr, _>(&mut store, "string-ret")? 1933 .call(&mut store, ()) 1934 .err() 1935 .unwrap(); 1936 assert!( 1937 err.to_string().contains("return pointer not aligned"), 1938 "{}", 1939 err 1940 ); 1941 1942 let err = instance(&mut store)? 1943 .get_typed_func::<(), WasmList<u32>, _>(&mut store, "list-u32-ret")? 1944 .call(&mut store, ()) 1945 .err() 1946 .unwrap(); 1947 assert!( 1948 err.to_string().contains("list pointer is not aligned"), 1949 "{}", 1950 err 1951 ); 1952 1953 Ok(()) 1954 } 1955 1956 #[test] 1957 fn drop_component_still_works() -> Result<()> { 1958 let component = r#" 1959 (component 1960 (import "f" (func $f)) 1961 1962 (core func $f_lower 1963 (canon lower (func $f)) 1964 ) 1965 (core module $m 1966 (import "" "" (func $f)) 1967 1968 (func $f2 1969 call $f 1970 call $f 1971 ) 1972 1973 (export "f" (func $f2)) 1974 ) 1975 (core instance $i (instantiate $m 1976 (with "" (instance 1977 (export "" (func $f_lower)) 1978 )) 1979 )) 1980 (func (export "f") 1981 (canon lift 1982 (core func $i "f") 1983 ) 1984 ) 1985 ) 1986 "#; 1987 1988 let (mut store, instance) = { 1989 let engine = super::engine(); 1990 let component = Component::new(&engine, component)?; 1991 let mut store = Store::new(&engine, 0); 1992 let mut linker = Linker::new(&engine); 1993 linker 1994 .root() 1995 .func_wrap("f", |mut store: StoreContextMut<'_, u32>| -> Result<()> { 1996 *store.data_mut() += 1; 1997 Ok(()) 1998 })?; 1999 let instance = linker.instantiate(&mut store, &component)?; 2000 (store, instance) 2001 }; 2002 2003 let f = instance.get_typed_func::<(), (), _>(&mut store, "f")?; 2004 assert_eq!(*store.data(), 0); 2005 f.call(&mut store, ())?; 2006 assert_eq!(*store.data(), 2); 2007 2008 Ok(()) 2009 } 2010 2011 #[test] 2012 fn raw_slice_of_various_types() -> Result<()> { 2013 let component = r#" 2014 (component 2015 (core module $m 2016 (memory (export "memory") 1) 2017 2018 (func (export "list8") (result i32) 2019 (call $setup_list (i32.const 16)) 2020 ) 2021 (func (export "list16") (result i32) 2022 (call $setup_list (i32.const 8)) 2023 ) 2024 (func (export "list32") (result i32) 2025 (call $setup_list (i32.const 4)) 2026 ) 2027 (func (export "list64") (result i32) 2028 (call $setup_list (i32.const 2)) 2029 ) 2030 2031 (func $setup_list (param i32) (result i32) 2032 (i32.store offset=0 (i32.const 100) (i32.const 8)) 2033 (i32.store offset=4 (i32.const 100) (local.get 0)) 2034 i32.const 100 2035 ) 2036 2037 (data (i32.const 8) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f") 2038 ) 2039 (core instance $i (instantiate $m)) 2040 (func (export "list-u8") (result (list u8)) 2041 (canon lift (core func $i "list8") (memory $i "memory")) 2042 ) 2043 (func (export "list-i8") (result (list s8)) 2044 (canon lift (core func $i "list8") (memory $i "memory")) 2045 ) 2046 (func (export "list-u16") (result (list u16)) 2047 (canon lift (core func $i "list16") (memory $i "memory")) 2048 ) 2049 (func (export "list-i16") (result (list s16)) 2050 (canon lift (core func $i "list16") (memory $i "memory")) 2051 ) 2052 (func (export "list-u32") (result (list u32)) 2053 (canon lift (core func $i "list32") (memory $i "memory")) 2054 ) 2055 (func (export "list-i32") (result (list s32)) 2056 (canon lift (core func $i "list32") (memory $i "memory")) 2057 ) 2058 (func (export "list-u64") (result (list u64)) 2059 (canon lift (core func $i "list64") (memory $i "memory")) 2060 ) 2061 (func (export "list-i64") (result (list s64)) 2062 (canon lift (core func $i "list64") (memory $i "memory")) 2063 ) 2064 ) 2065 "#; 2066 2067 let (mut store, instance) = { 2068 let engine = super::engine(); 2069 let component = Component::new(&engine, component)?; 2070 let mut store = Store::new(&engine, ()); 2071 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 2072 (store, instance) 2073 }; 2074 2075 let list = instance 2076 .get_typed_func::<(), WasmList<u8>, _>(&mut store, "list-u8")? 2077 .call_and_post_return(&mut store, ())?; 2078 assert_eq!( 2079 list.as_le_slice(&store), 2080 [ 2081 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 2082 0x0e, 0x0f, 2083 ] 2084 ); 2085 let list = instance 2086 .get_typed_func::<(), WasmList<i8>, _>(&mut store, "list-i8")? 2087 .call_and_post_return(&mut store, ())?; 2088 assert_eq!( 2089 list.as_le_slice(&store), 2090 [ 2091 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 2092 0x0e, 0x0f, 2093 ] 2094 ); 2095 2096 let list = instance 2097 .get_typed_func::<(), WasmList<u16>, _>(&mut store, "list-u16")? 2098 .call_and_post_return(&mut store, ())?; 2099 assert_eq!( 2100 list.as_le_slice(&store), 2101 [ 2102 u16::to_le(0x01_00), 2103 u16::to_le(0x03_02), 2104 u16::to_le(0x05_04), 2105 u16::to_le(0x07_06), 2106 u16::to_le(0x09_08), 2107 u16::to_le(0x0b_0a), 2108 u16::to_le(0x0d_0c), 2109 u16::to_le(0x0f_0e), 2110 ] 2111 ); 2112 let list = instance 2113 .get_typed_func::<(), WasmList<i16>, _>(&mut store, "list-i16")? 2114 .call_and_post_return(&mut store, ())?; 2115 assert_eq!( 2116 list.as_le_slice(&store), 2117 [ 2118 i16::to_le(0x01_00), 2119 i16::to_le(0x03_02), 2120 i16::to_le(0x05_04), 2121 i16::to_le(0x07_06), 2122 i16::to_le(0x09_08), 2123 i16::to_le(0x0b_0a), 2124 i16::to_le(0x0d_0c), 2125 i16::to_le(0x0f_0e), 2126 ] 2127 ); 2128 let list = instance 2129 .get_typed_func::<(), WasmList<u32>, _>(&mut store, "list-u32")? 2130 .call_and_post_return(&mut store, ())?; 2131 assert_eq!( 2132 list.as_le_slice(&store), 2133 [ 2134 u32::to_le(0x03_02_01_00), 2135 u32::to_le(0x07_06_05_04), 2136 u32::to_le(0x0b_0a_09_08), 2137 u32::to_le(0x0f_0e_0d_0c), 2138 ] 2139 ); 2140 let list = instance 2141 .get_typed_func::<(), WasmList<i32>, _>(&mut store, "list-i32")? 2142 .call_and_post_return(&mut store, ())?; 2143 assert_eq!( 2144 list.as_le_slice(&store), 2145 [ 2146 i32::to_le(0x03_02_01_00), 2147 i32::to_le(0x07_06_05_04), 2148 i32::to_le(0x0b_0a_09_08), 2149 i32::to_le(0x0f_0e_0d_0c), 2150 ] 2151 ); 2152 let list = instance 2153 .get_typed_func::<(), WasmList<u64>, _>(&mut store, "list-u64")? 2154 .call_and_post_return(&mut store, ())?; 2155 assert_eq!( 2156 list.as_le_slice(&store), 2157 [ 2158 u64::to_le(0x07_06_05_04_03_02_01_00), 2159 u64::to_le(0x0f_0e_0d_0c_0b_0a_09_08), 2160 ] 2161 ); 2162 let list = instance 2163 .get_typed_func::<(), WasmList<i64>, _>(&mut store, "list-i64")? 2164 .call_and_post_return(&mut store, ())?; 2165 assert_eq!( 2166 list.as_le_slice(&store), 2167 [ 2168 i64::to_le(0x07_06_05_04_03_02_01_00), 2169 i64::to_le(0x0f_0e_0d_0c_0b_0a_09_08), 2170 ] 2171 ); 2172 2173 Ok(()) 2174 } 2175 2176 #[test] 2177 fn lower_then_lift() -> Result<()> { 2178 // First test simple integers when the import/export ABI happen to line up 2179 let component = r#" 2180 (component $c 2181 (import "f" (func $f (result u32))) 2182 2183 (core func $f_lower 2184 (canon lower (func $f)) 2185 ) 2186 (func $f2 (result s32) 2187 (canon lift (core func $f_lower)) 2188 ) 2189 (export "f" (func $f2)) 2190 ) 2191 "#; 2192 2193 let engine = super::engine(); 2194 let component = Component::new(&engine, component)?; 2195 let mut store = Store::new(&engine, ()); 2196 let mut linker = Linker::new(&engine); 2197 linker.root().func_wrap("f", || Ok(2u32))?; 2198 let instance = linker.instantiate(&mut store, &component)?; 2199 2200 let f = instance.get_typed_func::<(), i32, _>(&mut store, "f")?; 2201 assert_eq!(f.call(&mut store, ())?, 2); 2202 2203 // First test strings when the import/export ABI happen to line up 2204 let component = format!( 2205 r#" 2206 (component $c 2207 (import "s" (func $f (param string))) 2208 2209 (core module $libc 2210 (memory (export "memory") 1) 2211 {REALLOC_AND_FREE} 2212 ) 2213 (core instance $libc (instantiate $libc)) 2214 2215 (core func $f_lower 2216 (canon lower (func $f) (memory $libc "memory")) 2217 ) 2218 (func $f2 (param string) 2219 (canon lift (core func $f_lower) 2220 (memory $libc "memory") 2221 (realloc (func $libc "realloc")) 2222 ) 2223 ) 2224 (export "f" (func $f2)) 2225 ) 2226 "# 2227 ); 2228 2229 let component = Component::new(&engine, component)?; 2230 let mut store = Store::new(&engine, ()); 2231 linker 2232 .root() 2233 .func_wrap("s", |store: StoreContextMut<'_, ()>, x: WasmStr| { 2234 assert_eq!(x.to_str(&store)?, "hello"); 2235 Ok(()) 2236 })?; 2237 let instance = linker.instantiate(&mut store, &component)?; 2238 2239 let f = instance.get_typed_func::<(&str,), (), _>(&mut store, "f")?; 2240 f.call(&mut store, ("hello",))?; 2241 2242 // Next test "type punning" where return values are reinterpreted just 2243 // because the return ABI happens to line up. 2244 let component = format!( 2245 r#" 2246 (component $c 2247 (import "s2" (func $f (param string) (result u32))) 2248 2249 (core module $libc 2250 (memory (export "memory") 1) 2251 {REALLOC_AND_FREE} 2252 ) 2253 (core instance $libc (instantiate $libc)) 2254 2255 (core func $f_lower 2256 (canon lower (func $f) (memory $libc "memory")) 2257 ) 2258 (func $f2 (param string) (result string) 2259 (canon lift (core func $f_lower) 2260 (memory $libc "memory") 2261 (realloc (func $libc "realloc")) 2262 ) 2263 ) 2264 (export "f" (func $f2)) 2265 ) 2266 "# 2267 ); 2268 2269 let component = Component::new(&engine, component)?; 2270 let mut store = Store::new(&engine, ()); 2271 linker 2272 .root() 2273 .func_wrap("s2", |store: StoreContextMut<'_, ()>, x: WasmStr| { 2274 assert_eq!(x.to_str(&store)?, "hello"); 2275 Ok(u32::MAX) 2276 })?; 2277 let instance = linker.instantiate(&mut store, &component)?; 2278 2279 let f = instance.get_typed_func::<(&str,), WasmStr, _>(&mut store, "f")?; 2280 let err = f.call(&mut store, ("hello",)).err().unwrap(); 2281 assert!( 2282 err.to_string().contains("return pointer not aligned"), 2283 "{}", 2284 err 2285 ); 2286 2287 Ok(()) 2288 } 2289 2290 #[test] 2291 fn errors_that_poison_instance() -> Result<()> { 2292 let component = format!( 2293 r#" 2294 (component $c 2295 (core module $m1 2296 (func (export "f1") unreachable) 2297 (func (export "f2")) 2298 ) 2299 (core instance $m1 (instantiate $m1)) 2300 (func (export "f1") (canon lift (core func $m1 "f1"))) 2301 (func (export "f2") (canon lift (core func $m1 "f2"))) 2302 2303 (core module $m2 2304 (func (export "f") (param i32 i32)) 2305 (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) 2306 (memory (export "m") 1) 2307 ) 2308 (core instance $m2 (instantiate $m2)) 2309 (func (export "f3") (param string) 2310 (canon lift (core func $m2 "f") (realloc (func $m2 "r")) (memory $m2 "m")) 2311 ) 2312 2313 (core module $m3 2314 (func (export "f") (result i32) i32.const 1) 2315 (memory (export "m") 1) 2316 ) 2317 (core instance $m3 (instantiate $m3)) 2318 (func (export "f4") (result string) 2319 (canon lift (core func $m3 "f") (memory $m3 "m")) 2320 ) 2321 ) 2322 "# 2323 ); 2324 2325 let engine = super::engine(); 2326 let component = Component::new(&engine, component)?; 2327 let mut store = Store::new(&engine, ()); 2328 let linker = Linker::new(&engine); 2329 let instance = linker.instantiate(&mut store, &component)?; 2330 let f1 = instance.get_typed_func::<(), (), _>(&mut store, "f1")?; 2331 let f2 = instance.get_typed_func::<(), (), _>(&mut store, "f2")?; 2332 assert_unreachable(f1.call(&mut store, ())); 2333 assert_poisoned(f1.call(&mut store, ())); 2334 assert_poisoned(f2.call(&mut store, ())); 2335 2336 let instance = linker.instantiate(&mut store, &component)?; 2337 let f3 = instance.get_typed_func::<(&str,), (), _>(&mut store, "f3")?; 2338 assert_unreachable(f3.call(&mut store, ("x",))); 2339 assert_poisoned(f3.call(&mut store, ("x",))); 2340 2341 let instance = linker.instantiate(&mut store, &component)?; 2342 let f4 = instance.get_typed_func::<(), WasmStr, _>(&mut store, "f4")?; 2343 assert!(f4.call(&mut store, ()).is_err()); 2344 assert_poisoned(f4.call(&mut store, ())); 2345 2346 return Ok(()); 2347 2348 #[track_caller] 2349 fn assert_unreachable<T>(err: Result<T>) { 2350 let err = match err { 2351 Ok(_) => panic!("expected an error"), 2352 Err(e) => e, 2353 }; 2354 assert_eq!( 2355 err.downcast::<Trap>().unwrap().trap_code(), 2356 Some(TrapCode::UnreachableCodeReached) 2357 ); 2358 } 2359 2360 #[track_caller] 2361 fn assert_poisoned<T>(err: Result<T>) { 2362 let err = match err { 2363 Ok(_) => panic!("expected an error"), 2364 Err(e) => e, 2365 }; 2366 assert!( 2367 err.to_string() 2368 .contains("cannot reenter component instance"), 2369 "{}", 2370 err, 2371 ); 2372 } 2373 } 2374 2375 #[test] 2376 fn run_export_with_internal_adapter() -> Result<()> { 2377 let component = r#" 2378 (component 2379 (type $t (func (param u32) (result u32))) 2380 (component $a 2381 (core module $m 2382 (func (export "add-five") (param i32) (result i32) 2383 local.get 0 2384 i32.const 5 2385 i32.add) 2386 ) 2387 (core instance $m (instantiate $m)) 2388 (func (export "add-five") (type $t) (canon lift (core func $m "add-five"))) 2389 ) 2390 (component $b 2391 (import "interface-0.1.0" (instance $i 2392 (export "add-five" (func (type $t))))) 2393 (core module $m 2394 (func $add-five (import "interface-0.1.0" "add-five") (param i32) (result i32)) 2395 (func) ;; causes index out of bounds 2396 (func (export "run") (result i32) i32.const 0 call $add-five) 2397 ) 2398 (core func $add-five (canon lower (func $i "add-five"))) 2399 (core instance $i (instantiate 0 2400 (with "interface-0.1.0" (instance 2401 (export "add-five" (func $add-five)) 2402 )) 2403 )) 2404 (func (result u32) (canon lift (core func $i "run"))) 2405 (export "run" (func 1)) 2406 ) 2407 (instance $a (instantiate $a)) 2408 (instance $b (instantiate $b (with "interface-0.1.0" (instance $a)))) 2409 (export "run" (func $b "run")) 2410 ) 2411 "#; 2412 let engine = super::engine(); 2413 let component = Component::new(&engine, component)?; 2414 let mut store = Store::new(&engine, ()); 2415 let linker = Linker::new(&engine); 2416 let instance = linker.instantiate(&mut store, &component)?; 2417 let run = instance.get_typed_func::<(), u32, _>(&mut store, "run")?; 2418 assert_eq!(run.call(&mut store, ())?, 5); 2419 Ok(()) 2420 } 2421