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