1 #![cfg(not(miri))] 2 3 use super::{REALLOC_AND_FREE, TypedFuncExt}; 4 use anyhow::Result; 5 use std::sync::Arc; 6 use wasmtime::component::*; 7 use wasmtime::{Config, Engine, Store, StoreContextMut, Trap}; 8 9 const CANON_32BIT_NAN: u32 = 0b01111111110000000000000000000000; 10 const CANON_64BIT_NAN: u64 = 0b0111111111111000000000000000000000000000000000000000000000000000; 11 12 #[test] 13 fn thunks() -> Result<()> { 14 let component = r#" 15 (component 16 (core module $m 17 (func (export "thunk")) 18 (func (export "thunk-trap") unreachable) 19 ) 20 (core instance $i (instantiate $m)) 21 (func (export "thunk") 22 (canon lift (core func $i "thunk")) 23 ) 24 (func (export "thunk-trap") 25 (canon lift (core func $i "thunk-trap")) 26 ) 27 ) 28 "#; 29 30 let engine = super::engine(); 31 let component = Component::new(&engine, component)?; 32 let mut store = Store::new(&engine, ()); 33 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 34 instance 35 .get_typed_func::<(), ()>(&mut store, "thunk")? 36 .call_and_post_return(&mut store, ())?; 37 let err = instance 38 .get_typed_func::<(), ()>(&mut store, "thunk-trap")? 39 .call(&mut store, ()) 40 .unwrap_err(); 41 assert_eq!(err.downcast::<Trap>()?, Trap::UnreachableCodeReached); 42 43 Ok(()) 44 } 45 46 #[test] 47 fn typecheck() -> Result<()> { 48 let component = r#" 49 (component 50 (core module $m 51 (func (export "thunk")) 52 (func (export "take-string") (param i32 i32)) 53 (func (export "two-args") (param i32 i32 i32)) 54 (func (export "ret-one") (result i32) unreachable) 55 56 (memory (export "memory") 1) 57 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 58 unreachable) 59 ) 60 (core instance $i (instantiate (module $m))) 61 (func (export "thunk") 62 (canon lift (core func $i "thunk")) 63 ) 64 (func (export "take-string") (param "a" string) 65 (canon lift (core func $i "take-string") (memory $i "memory") (realloc (func $i "realloc"))) 66 ) 67 (func (export "take-two-args") (param "a" s32) (param "b" (list u8)) 68 (canon lift (core func $i "two-args") (memory $i "memory") (realloc (func $i "realloc"))) 69 ) 70 (func (export "ret-tuple") (result (tuple u8 s8)) 71 (canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc"))) 72 ) 73 (func (export "ret-tuple1") (result (tuple u32)) 74 (canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc"))) 75 ) 76 (func (export "ret-string") (result string) 77 (canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc"))) 78 ) 79 (func (export "ret-list-u8") (result (list u8)) 80 (canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc"))) 81 ) 82 ) 83 "#; 84 85 let engine = Engine::default(); 86 let component = Component::new(&engine, component)?; 87 let mut store = Store::new(&engine, ()); 88 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 89 let thunk = instance.get_func(&mut store, "thunk").unwrap(); 90 let take_string = instance.get_func(&mut store, "take-string").unwrap(); 91 let take_two_args = instance.get_func(&mut store, "take-two-args").unwrap(); 92 let ret_tuple = instance.get_func(&mut store, "ret-tuple").unwrap(); 93 let ret_tuple1 = instance.get_func(&mut store, "ret-tuple1").unwrap(); 94 let ret_string = instance.get_func(&mut store, "ret-string").unwrap(); 95 let ret_list_u8 = instance.get_func(&mut store, "ret-list-u8").unwrap(); 96 assert!(thunk.typed::<(), (u32,)>(&store).is_err()); 97 assert!(thunk.typed::<(u32,), ()>(&store).is_err()); 98 assert!(thunk.typed::<(), ()>(&store).is_ok()); 99 assert!(take_string.typed::<(), ()>(&store).is_err()); 100 assert!(take_string.typed::<(String,), ()>(&store).is_ok()); 101 assert!(take_string.typed::<(&str,), ()>(&store).is_ok()); 102 assert!(take_string.typed::<(&[u8],), ()>(&store).is_err()); 103 assert!(take_two_args.typed::<(), ()>(&store).is_err()); 104 assert!(take_two_args.typed::<(i32, &[u8]), (u32,)>(&store).is_err()); 105 assert!(take_two_args.typed::<(u32, &[u8]), ()>(&store).is_err()); 106 assert!(take_two_args.typed::<(i32, &[u8]), ()>(&store).is_ok()); 107 assert!(ret_tuple.typed::<(), ()>(&store).is_err()); 108 assert!(ret_tuple.typed::<(), (u8,)>(&store).is_err()); 109 assert!(ret_tuple.typed::<(), ((u8, i8),)>(&store).is_ok()); 110 assert!(ret_tuple1.typed::<(), ((u32,),)>(&store).is_ok()); 111 assert!(ret_tuple1.typed::<(), (u32,)>(&store).is_err()); 112 assert!(ret_string.typed::<(), ()>(&store).is_err()); 113 assert!(ret_string.typed::<(), (WasmStr,)>(&store).is_ok()); 114 assert!(ret_list_u8.typed::<(), (WasmList<u16>,)>(&store).is_err()); 115 assert!(ret_list_u8.typed::<(), (WasmList<i8>,)>(&store).is_err()); 116 assert!(ret_list_u8.typed::<(), (WasmList<u8>,)>(&store).is_ok()); 117 118 Ok(()) 119 } 120 121 #[test] 122 fn integers() -> Result<()> { 123 let component = r#" 124 (component 125 (core module $m 126 (func (export "take-i32-100") (param i32) 127 local.get 0 128 i32.const 100 129 i32.eq 130 br_if 0 131 unreachable 132 ) 133 (func (export "take-i64-100") (param i64) 134 local.get 0 135 i64.const 100 136 i64.eq 137 br_if 0 138 unreachable 139 ) 140 (func (export "ret-i32-0") (result i32) i32.const 0) 141 (func (export "ret-i64-0") (result i64) i64.const 0) 142 (func (export "ret-i32-minus-1") (result i32) i32.const -1) 143 (func (export "ret-i64-minus-1") (result i64) i64.const -1) 144 (func (export "ret-i32-100000") (result i32) i32.const 100000) 145 ) 146 (core instance $i (instantiate (module $m))) 147 (func (export "take-u8") (param "a" u8) (canon lift (core func $i "take-i32-100"))) 148 (func (export "take-s8") (param "a" s8) (canon lift (core func $i "take-i32-100"))) 149 (func (export "take-u16") (param "a" u16) (canon lift (core func $i "take-i32-100"))) 150 (func (export "take-s16") (param "a" s16) (canon lift (core func $i "take-i32-100"))) 151 (func (export "take-u32") (param "a" u32) (canon lift (core func $i "take-i32-100"))) 152 (func (export "take-s32") (param "a" s32) (canon lift (core func $i "take-i32-100"))) 153 (func (export "take-u64") (param "a" u64) (canon lift (core func $i "take-i64-100"))) 154 (func (export "take-s64") (param "a" s64) (canon lift (core func $i "take-i64-100"))) 155 156 (func (export "ret-u8") (result u8) (canon lift (core func $i "ret-i32-0"))) 157 (func (export "ret-s8") (result s8) (canon lift (core func $i "ret-i32-0"))) 158 (func (export "ret-u16") (result u16) (canon lift (core func $i "ret-i32-0"))) 159 (func (export "ret-s16") (result s16) (canon lift (core func $i "ret-i32-0"))) 160 (func (export "ret-u32") (result u32) (canon lift (core func $i "ret-i32-0"))) 161 (func (export "ret-s32") (result s32) (canon lift (core func $i "ret-i32-0"))) 162 (func (export "ret-u64") (result u64) (canon lift (core func $i "ret-i64-0"))) 163 (func (export "ret-s64") (result s64) (canon lift (core func $i "ret-i64-0"))) 164 165 (func (export "retm1-u8") (result u8) (canon lift (core func $i "ret-i32-minus-1"))) 166 (func (export "retm1-s8") (result s8) (canon lift (core func $i "ret-i32-minus-1"))) 167 (func (export "retm1-u16") (result u16) (canon lift (core func $i "ret-i32-minus-1"))) 168 (func (export "retm1-s16") (result s16) (canon lift (core func $i "ret-i32-minus-1"))) 169 (func (export "retm1-u32") (result u32) (canon lift (core func $i "ret-i32-minus-1"))) 170 (func (export "retm1-s32") (result s32) (canon lift (core func $i "ret-i32-minus-1"))) 171 (func (export "retm1-u64") (result u64) (canon lift (core func $i "ret-i64-minus-1"))) 172 (func (export "retm1-s64") (result s64) (canon lift (core func $i "ret-i64-minus-1"))) 173 174 (func (export "retbig-u8") (result u8) (canon lift (core func $i "ret-i32-100000"))) 175 (func (export "retbig-s8") (result s8) (canon lift (core func $i "ret-i32-100000"))) 176 (func (export "retbig-u16") (result u16) (canon lift (core func $i "ret-i32-100000"))) 177 (func (export "retbig-s16") (result s16) (canon lift (core func $i "ret-i32-100000"))) 178 (func (export "retbig-u32") (result u32) (canon lift (core func $i "ret-i32-100000"))) 179 (func (export "retbig-s32") (result s32) (canon lift (core func $i "ret-i32-100000"))) 180 ) 181 "#; 182 183 let engine = super::engine(); 184 let component = Component::new(&engine, component)?; 185 let mut store = Store::new(&engine, ()); 186 let new_instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component); 187 let instance = new_instance(&mut store)?; 188 189 // Passing in 100 is valid for all primitives 190 instance 191 .get_typed_func::<(u8,), ()>(&mut store, "take-u8")? 192 .call_and_post_return(&mut store, (100,))?; 193 instance 194 .get_typed_func::<(i8,), ()>(&mut store, "take-s8")? 195 .call_and_post_return(&mut store, (100,))?; 196 instance 197 .get_typed_func::<(u16,), ()>(&mut store, "take-u16")? 198 .call_and_post_return(&mut store, (100,))?; 199 instance 200 .get_typed_func::<(i16,), ()>(&mut store, "take-s16")? 201 .call_and_post_return(&mut store, (100,))?; 202 instance 203 .get_typed_func::<(u32,), ()>(&mut store, "take-u32")? 204 .call_and_post_return(&mut store, (100,))?; 205 instance 206 .get_typed_func::<(i32,), ()>(&mut store, "take-s32")? 207 .call_and_post_return(&mut store, (100,))?; 208 instance 209 .get_typed_func::<(u64,), ()>(&mut store, "take-u64")? 210 .call_and_post_return(&mut store, (100,))?; 211 instance 212 .get_typed_func::<(i64,), ()>(&mut store, "take-s64")? 213 .call_and_post_return(&mut store, (100,))?; 214 215 // This specific wasm instance traps if any value other than 100 is passed 216 new_instance(&mut store)? 217 .get_typed_func::<(u8,), ()>(&mut store, "take-u8")? 218 .call(&mut store, (101,)) 219 .unwrap_err() 220 .downcast::<Trap>()?; 221 new_instance(&mut store)? 222 .get_typed_func::<(i8,), ()>(&mut store, "take-s8")? 223 .call(&mut store, (101,)) 224 .unwrap_err() 225 .downcast::<Trap>()?; 226 new_instance(&mut store)? 227 .get_typed_func::<(u16,), ()>(&mut store, "take-u16")? 228 .call(&mut store, (101,)) 229 .unwrap_err() 230 .downcast::<Trap>()?; 231 new_instance(&mut store)? 232 .get_typed_func::<(i16,), ()>(&mut store, "take-s16")? 233 .call(&mut store, (101,)) 234 .unwrap_err() 235 .downcast::<Trap>()?; 236 new_instance(&mut store)? 237 .get_typed_func::<(u32,), ()>(&mut store, "take-u32")? 238 .call(&mut store, (101,)) 239 .unwrap_err() 240 .downcast::<Trap>()?; 241 new_instance(&mut store)? 242 .get_typed_func::<(i32,), ()>(&mut store, "take-s32")? 243 .call(&mut store, (101,)) 244 .unwrap_err() 245 .downcast::<Trap>()?; 246 new_instance(&mut store)? 247 .get_typed_func::<(u64,), ()>(&mut store, "take-u64")? 248 .call(&mut store, (101,)) 249 .unwrap_err() 250 .downcast::<Trap>()?; 251 new_instance(&mut store)? 252 .get_typed_func::<(i64,), ()>(&mut store, "take-s64")? 253 .call(&mut store, (101,)) 254 .unwrap_err() 255 .downcast::<Trap>()?; 256 257 // Zero can be returned as any integer 258 assert_eq!( 259 instance 260 .get_typed_func::<(), (u8,)>(&mut store, "ret-u8")? 261 .call_and_post_return(&mut store, ())?, 262 (0,) 263 ); 264 assert_eq!( 265 instance 266 .get_typed_func::<(), (i8,)>(&mut store, "ret-s8")? 267 .call_and_post_return(&mut store, ())?, 268 (0,) 269 ); 270 assert_eq!( 271 instance 272 .get_typed_func::<(), (u16,)>(&mut store, "ret-u16")? 273 .call_and_post_return(&mut store, ())?, 274 (0,) 275 ); 276 assert_eq!( 277 instance 278 .get_typed_func::<(), (i16,)>(&mut store, "ret-s16")? 279 .call_and_post_return(&mut store, ())?, 280 (0,) 281 ); 282 assert_eq!( 283 instance 284 .get_typed_func::<(), (u32,)>(&mut store, "ret-u32")? 285 .call_and_post_return(&mut store, ())?, 286 (0,) 287 ); 288 assert_eq!( 289 instance 290 .get_typed_func::<(), (i32,)>(&mut store, "ret-s32")? 291 .call_and_post_return(&mut store, ())?, 292 (0,) 293 ); 294 assert_eq!( 295 instance 296 .get_typed_func::<(), (u64,)>(&mut store, "ret-u64")? 297 .call_and_post_return(&mut store, ())?, 298 (0,) 299 ); 300 assert_eq!( 301 instance 302 .get_typed_func::<(), (i64,)>(&mut store, "ret-s64")? 303 .call_and_post_return(&mut store, ())?, 304 (0,) 305 ); 306 307 // Returning -1 should reinterpret the bytes as defined by each type. 308 assert_eq!( 309 instance 310 .get_typed_func::<(), (u8,)>(&mut store, "retm1-u8")? 311 .call_and_post_return(&mut store, ())?, 312 (0xff,) 313 ); 314 assert_eq!( 315 instance 316 .get_typed_func::<(), (i8,)>(&mut store, "retm1-s8")? 317 .call_and_post_return(&mut store, ())?, 318 (-1,) 319 ); 320 assert_eq!( 321 instance 322 .get_typed_func::<(), (u16,)>(&mut store, "retm1-u16")? 323 .call_and_post_return(&mut store, ())?, 324 (0xffff,) 325 ); 326 assert_eq!( 327 instance 328 .get_typed_func::<(), (i16,)>(&mut store, "retm1-s16")? 329 .call_and_post_return(&mut store, ())?, 330 (-1,) 331 ); 332 assert_eq!( 333 instance 334 .get_typed_func::<(), (u32,)>(&mut store, "retm1-u32")? 335 .call_and_post_return(&mut store, ())?, 336 (0xffffffff,) 337 ); 338 assert_eq!( 339 instance 340 .get_typed_func::<(), (i32,)>(&mut store, "retm1-s32")? 341 .call_and_post_return(&mut store, ())?, 342 (-1,) 343 ); 344 assert_eq!( 345 instance 346 .get_typed_func::<(), (u64,)>(&mut store, "retm1-u64")? 347 .call_and_post_return(&mut store, ())?, 348 (0xffffffff_ffffffff,) 349 ); 350 assert_eq!( 351 instance 352 .get_typed_func::<(), (i64,)>(&mut store, "retm1-s64")? 353 .call_and_post_return(&mut store, ())?, 354 (-1,) 355 ); 356 357 // Returning 100000 should chop off bytes as necessary 358 let ret: u32 = 100000; 359 assert_eq!( 360 instance 361 .get_typed_func::<(), (u8,)>(&mut store, "retbig-u8")? 362 .call_and_post_return(&mut store, ())?, 363 (ret as u8,), 364 ); 365 assert_eq!( 366 instance 367 .get_typed_func::<(), (i8,)>(&mut store, "retbig-s8")? 368 .call_and_post_return(&mut store, ())?, 369 (ret as i8,), 370 ); 371 assert_eq!( 372 instance 373 .get_typed_func::<(), (u16,)>(&mut store, "retbig-u16")? 374 .call_and_post_return(&mut store, ())?, 375 (ret as u16,), 376 ); 377 assert_eq!( 378 instance 379 .get_typed_func::<(), (i16,)>(&mut store, "retbig-s16")? 380 .call_and_post_return(&mut store, ())?, 381 (ret as i16,), 382 ); 383 assert_eq!( 384 instance 385 .get_typed_func::<(), (u32,)>(&mut store, "retbig-u32")? 386 .call_and_post_return(&mut store, ())?, 387 (ret,), 388 ); 389 assert_eq!( 390 instance 391 .get_typed_func::<(), (i32,)>(&mut store, "retbig-s32")? 392 .call_and_post_return(&mut store, ())?, 393 (ret as i32,), 394 ); 395 396 Ok(()) 397 } 398 399 #[test] 400 fn type_layers() -> Result<()> { 401 let component = r#" 402 (component 403 (core module $m 404 (func (export "take-i32-100") (param i32) 405 local.get 0 406 i32.const 2 407 i32.eq 408 br_if 0 409 unreachable 410 ) 411 ) 412 (core instance $i (instantiate $m)) 413 (func (export "take-u32") (param "a" u32) (canon lift (core func $i "take-i32-100"))) 414 ) 415 "#; 416 417 let engine = super::engine(); 418 let component = Component::new(&engine, component)?; 419 let mut store = Store::new(&engine, ()); 420 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 421 422 instance 423 .get_typed_func::<(Box<u32>,), ()>(&mut store, "take-u32")? 424 .call_and_post_return(&mut store, (Box::new(2),))?; 425 instance 426 .get_typed_func::<(&u32,), ()>(&mut store, "take-u32")? 427 .call_and_post_return(&mut store, (&2,))?; 428 instance 429 .get_typed_func::<(Arc<u32>,), ()>(&mut store, "take-u32")? 430 .call_and_post_return(&mut store, (Arc::new(2),))?; 431 instance 432 .get_typed_func::<(&Box<Arc<Box<u32>>>,), ()>(&mut store, "take-u32")? 433 .call_and_post_return(&mut store, (&Box::new(Arc::new(Box::new(2))),))?; 434 435 Ok(()) 436 } 437 438 #[test] 439 fn floats() -> Result<()> { 440 let component = r#" 441 (component 442 (core module $m 443 (func (export "i32.reinterpret_f32") (param f32) (result i32) 444 local.get 0 445 i32.reinterpret_f32 446 ) 447 (func (export "i64.reinterpret_f64") (param f64) (result i64) 448 local.get 0 449 i64.reinterpret_f64 450 ) 451 (func (export "f32.reinterpret_i32") (param i32) (result f32) 452 local.get 0 453 f32.reinterpret_i32 454 ) 455 (func (export "f64.reinterpret_i64") (param i64) (result f64) 456 local.get 0 457 f64.reinterpret_i64 458 ) 459 ) 460 (core instance $i (instantiate $m)) 461 462 (func (export "f32-to-u32") (param "a" float32) (result u32) 463 (canon lift (core func $i "i32.reinterpret_f32")) 464 ) 465 (func (export "f64-to-u64") (param "a" float64) (result u64) 466 (canon lift (core func $i "i64.reinterpret_f64")) 467 ) 468 (func (export "u32-to-f32") (param "a" u32) (result float32) 469 (canon lift (core func $i "f32.reinterpret_i32")) 470 ) 471 (func (export "u64-to-f64") (param "a" u64) (result float64) 472 (canon lift (core func $i "f64.reinterpret_i64")) 473 ) 474 ) 475 "#; 476 477 let engine = super::engine(); 478 let component = Component::new(&engine, component)?; 479 let mut store = Store::new(&engine, ()); 480 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 481 let f32_to_u32 = instance.get_typed_func::<(f32,), (u32,)>(&mut store, "f32-to-u32")?; 482 let f64_to_u64 = instance.get_typed_func::<(f64,), (u64,)>(&mut store, "f64-to-u64")?; 483 let u32_to_f32 = instance.get_typed_func::<(u32,), (f32,)>(&mut store, "u32-to-f32")?; 484 let u64_to_f64 = instance.get_typed_func::<(u64,), (f64,)>(&mut store, "u64-to-f64")?; 485 486 assert_eq!(f32_to_u32.call(&mut store, (1.0,))?, (1.0f32.to_bits(),)); 487 f32_to_u32.post_return(&mut store)?; 488 assert_eq!(f64_to_u64.call(&mut store, (2.0,))?, (2.0f64.to_bits(),)); 489 f64_to_u64.post_return(&mut store)?; 490 assert_eq!(u32_to_f32.call(&mut store, (3.0f32.to_bits(),))?, (3.0,)); 491 u32_to_f32.post_return(&mut store)?; 492 assert_eq!(u64_to_f64.call(&mut store, (4.0f64.to_bits(),))?, (4.0,)); 493 u64_to_f64.post_return(&mut store)?; 494 495 assert_eq!( 496 u32_to_f32 497 .call(&mut store, (CANON_32BIT_NAN | 1,))? 498 .0 499 .to_bits(), 500 CANON_32BIT_NAN | 1 501 ); 502 u32_to_f32.post_return(&mut store)?; 503 assert_eq!( 504 u64_to_f64 505 .call(&mut store, (CANON_64BIT_NAN | 1,))? 506 .0 507 .to_bits(), 508 CANON_64BIT_NAN | 1, 509 ); 510 u64_to_f64.post_return(&mut store)?; 511 512 assert_eq!( 513 f32_to_u32.call(&mut store, (f32::from_bits(CANON_32BIT_NAN | 1),))?, 514 (CANON_32BIT_NAN | 1,) 515 ); 516 f32_to_u32.post_return(&mut store)?; 517 assert_eq!( 518 f64_to_u64.call(&mut store, (f64::from_bits(CANON_64BIT_NAN | 1),))?, 519 (CANON_64BIT_NAN | 1,) 520 ); 521 f64_to_u64.post_return(&mut store)?; 522 523 Ok(()) 524 } 525 526 #[test] 527 fn bools() -> Result<()> { 528 let component = r#" 529 (component 530 (core module $m 531 (func (export "pass") (param i32) (result i32) local.get 0) 532 ) 533 (core instance $i (instantiate $m)) 534 535 (func (export "u32-to-bool") (param "a" u32) (result bool) 536 (canon lift (core func $i "pass")) 537 ) 538 (func (export "bool-to-u32") (param "a" bool) (result u32) 539 (canon lift (core func $i "pass")) 540 ) 541 ) 542 "#; 543 544 let engine = super::engine(); 545 let component = Component::new(&engine, component)?; 546 let mut store = Store::new(&engine, ()); 547 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 548 let u32_to_bool = instance.get_typed_func::<(u32,), (bool,)>(&mut store, "u32-to-bool")?; 549 let bool_to_u32 = instance.get_typed_func::<(bool,), (u32,)>(&mut store, "bool-to-u32")?; 550 551 assert_eq!(bool_to_u32.call(&mut store, (false,))?, (0,)); 552 bool_to_u32.post_return(&mut store)?; 553 assert_eq!(bool_to_u32.call(&mut store, (true,))?, (1,)); 554 bool_to_u32.post_return(&mut store)?; 555 assert_eq!(u32_to_bool.call(&mut store, (0,))?, (false,)); 556 u32_to_bool.post_return(&mut store)?; 557 assert_eq!(u32_to_bool.call(&mut store, (1,))?, (true,)); 558 u32_to_bool.post_return(&mut store)?; 559 assert_eq!(u32_to_bool.call(&mut store, (2,))?, (true,)); 560 u32_to_bool.post_return(&mut store)?; 561 562 Ok(()) 563 } 564 565 #[test] 566 fn chars() -> Result<()> { 567 let component = r#" 568 (component 569 (core module $m 570 (func (export "pass") (param i32) (result i32) local.get 0) 571 ) 572 (core instance $i (instantiate $m)) 573 574 (func (export "u32-to-char") (param "a" u32) (result char) 575 (canon lift (core func $i "pass")) 576 ) 577 (func (export "char-to-u32") (param "a" char) (result u32) 578 (canon lift (core func $i "pass")) 579 ) 580 ) 581 "#; 582 583 let engine = super::engine(); 584 let component = Component::new(&engine, component)?; 585 let mut store = Store::new(&engine, ()); 586 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 587 let u32_to_char = instance.get_typed_func::<(u32,), (char,)>(&mut store, "u32-to-char")?; 588 let char_to_u32 = instance.get_typed_func::<(char,), (u32,)>(&mut store, "char-to-u32")?; 589 590 let mut roundtrip = |x: char| -> Result<()> { 591 assert_eq!(char_to_u32.call(&mut store, (x,))?, (x as u32,)); 592 char_to_u32.post_return(&mut store)?; 593 assert_eq!(u32_to_char.call(&mut store, (x as u32,))?, (x,)); 594 u32_to_char.post_return(&mut store)?; 595 Ok(()) 596 }; 597 598 roundtrip('x')?; 599 roundtrip('a')?; 600 roundtrip('\0')?; 601 roundtrip('\n')?; 602 roundtrip('')?; 603 604 let u32_to_char = |store: &mut Store<()>| { 605 Linker::new(&engine) 606 .instantiate(&mut *store, &component)? 607 .get_typed_func::<(u32,), (char,)>(&mut *store, "u32-to-char") 608 }; 609 let err = u32_to_char(&mut store)? 610 .call(&mut store, (0xd800,)) 611 .unwrap_err(); 612 assert!(err.to_string().contains("integer out of range"), "{}", err); 613 let err = u32_to_char(&mut store)? 614 .call(&mut store, (0xdfff,)) 615 .unwrap_err(); 616 assert!(err.to_string().contains("integer out of range"), "{}", err); 617 let err = u32_to_char(&mut store)? 618 .call(&mut store, (0x110000,)) 619 .unwrap_err(); 620 assert!(err.to_string().contains("integer out of range"), "{}", err); 621 let err = u32_to_char(&mut store)? 622 .call(&mut store, (u32::MAX,)) 623 .unwrap_err(); 624 assert!(err.to_string().contains("integer out of range"), "{}", err); 625 626 Ok(()) 627 } 628 629 #[test] 630 fn tuple_result() -> Result<()> { 631 let component = r#" 632 (component 633 (core module $m 634 (memory (export "memory") 1) 635 (func (export "foo") (param i32 i32 f32 f64) (result i32) 636 (local $base i32) 637 (local.set $base (i32.const 8)) 638 (i32.store8 offset=0 (local.get $base) (local.get 0)) 639 (i32.store16 offset=2 (local.get $base) (local.get 1)) 640 (f32.store offset=4 (local.get $base) (local.get 2)) 641 (f64.store offset=8 (local.get $base) (local.get 3)) 642 local.get $base 643 ) 644 645 (func (export "invalid") (result i32) 646 i32.const -8 647 ) 648 ) 649 (core instance $i (instantiate $m)) 650 651 (type $result (tuple s8 u16 float32 float64)) 652 (func (export "tuple") 653 (param "a" s8) (param "b" u16) (param "c" float32) (param "d" float64) (result $result) 654 (canon lift (core func $i "foo") (memory $i "memory")) 655 ) 656 (func (export "invalid") (result $result) 657 (canon lift (core func $i "invalid") (memory $i "memory")) 658 ) 659 ) 660 "#; 661 662 let engine = super::engine(); 663 let component = Component::new(&engine, component)?; 664 let mut store = Store::new(&engine, ()); 665 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 666 667 let input = (-1, 100, 3.0, 100.0); 668 let output = instance 669 .get_typed_func::<(i8, u16, f32, f64), ((i8, u16, f32, f64),)>(&mut store, "tuple")? 670 .call_and_post_return(&mut store, input)?; 671 assert_eq!((input,), output); 672 673 let invalid_func = 674 instance.get_typed_func::<(), ((i8, u16, f32, f64),)>(&mut store, "invalid")?; 675 let err = invalid_func.call(&mut store, ()).err().unwrap(); 676 assert!( 677 err.to_string().contains("pointer out of bounds of memory"), 678 "{}", 679 err 680 ); 681 682 Ok(()) 683 } 684 685 #[test] 686 fn strings() -> Result<()> { 687 let component = format!( 688 r#"(component 689 (core module $m 690 (memory (export "memory") 1) 691 (func (export "roundtrip") (param i32 i32) (result i32) 692 (local $base i32) 693 (local.set $base 694 (call $realloc 695 (i32.const 0) 696 (i32.const 0) 697 (i32.const 4) 698 (i32.const 8))) 699 (i32.store offset=0 700 (local.get $base) 701 (local.get 0)) 702 (i32.store offset=4 703 (local.get $base) 704 (local.get 1)) 705 (local.get $base) 706 ) 707 708 {REALLOC_AND_FREE} 709 ) 710 (core instance $i (instantiate $m)) 711 712 (func (export "list8-to-str") (param "a" (list u8)) (result string) 713 (canon lift 714 (core func $i "roundtrip") 715 (memory $i "memory") 716 (realloc (func $i "realloc")) 717 ) 718 ) 719 (func (export "str-to-list8") (param "a" string) (result (list u8)) 720 (canon lift 721 (core func $i "roundtrip") 722 (memory $i "memory") 723 (realloc (func $i "realloc")) 724 ) 725 ) 726 (func (export "list16-to-str") (param "a" (list u16)) (result string) 727 (canon lift 728 (core func $i "roundtrip") 729 string-encoding=utf16 730 (memory $i "memory") 731 (realloc (func $i "realloc")) 732 ) 733 ) 734 (func (export "str-to-list16") (param "a" string) (result (list u16)) 735 (canon lift 736 (core func $i "roundtrip") 737 string-encoding=utf16 738 (memory $i "memory") 739 (realloc (func $i "realloc")) 740 ) 741 ) 742 )"# 743 ); 744 745 let engine = super::engine(); 746 let component = Component::new(&engine, component)?; 747 let mut store = Store::new(&engine, ()); 748 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 749 let list8_to_str = 750 instance.get_typed_func::<(&[u8],), (WasmStr,)>(&mut store, "list8-to-str")?; 751 let str_to_list8 = 752 instance.get_typed_func::<(&str,), (WasmList<u8>,)>(&mut store, "str-to-list8")?; 753 let list16_to_str = 754 instance.get_typed_func::<(&[u16],), (WasmStr,)>(&mut store, "list16-to-str")?; 755 let str_to_list16 = 756 instance.get_typed_func::<(&str,), (WasmList<u16>,)>(&mut store, "str-to-list16")?; 757 758 let mut roundtrip = |x: &str| -> Result<()> { 759 let ret = list8_to_str.call(&mut store, (x.as_bytes(),))?.0; 760 assert_eq!(ret.to_str(&store)?, x); 761 list8_to_str.post_return(&mut store)?; 762 763 let utf16 = x.encode_utf16().collect::<Vec<_>>(); 764 let ret = list16_to_str.call(&mut store, (&utf16[..],))?.0; 765 assert_eq!(ret.to_str(&store)?, x); 766 list16_to_str.post_return(&mut store)?; 767 768 let ret = str_to_list8.call(&mut store, (x,))?.0; 769 assert_eq!( 770 ret.iter(&mut store).collect::<Result<Vec<_>>>()?, 771 x.as_bytes() 772 ); 773 str_to_list8.post_return(&mut store)?; 774 775 let ret = str_to_list16.call(&mut store, (x,))?.0; 776 assert_eq!(ret.iter(&mut store).collect::<Result<Vec<_>>>()?, utf16,); 777 str_to_list16.post_return(&mut store)?; 778 779 Ok(()) 780 }; 781 782 roundtrip("")?; 783 roundtrip("foo")?; 784 roundtrip("hello there")?; 785 roundtrip("")?; 786 roundtrip("Löwe 老虎 Léopard")?; 787 788 let ret = list8_to_str.call(&mut store, (b"\xff",))?.0; 789 let err = ret.to_str(&store).unwrap_err(); 790 assert!(err.to_string().contains("invalid utf-8"), "{}", err); 791 list8_to_str.post_return(&mut store)?; 792 793 let ret = list8_to_str 794 .call(&mut store, (b"hello there \xff invalid",))? 795 .0; 796 let err = ret.to_str(&store).unwrap_err(); 797 assert!(err.to_string().contains("invalid utf-8"), "{}", err); 798 list8_to_str.post_return(&mut store)?; 799 800 let ret = list16_to_str.call(&mut store, (&[0xd800],))?.0; 801 let err = ret.to_str(&store).unwrap_err(); 802 assert!(err.to_string().contains("unpaired surrogate"), "{}", err); 803 list16_to_str.post_return(&mut store)?; 804 805 let ret = list16_to_str.call(&mut store, (&[0xdfff],))?.0; 806 let err = ret.to_str(&store).unwrap_err(); 807 assert!(err.to_string().contains("unpaired surrogate"), "{}", err); 808 list16_to_str.post_return(&mut store)?; 809 810 let ret = list16_to_str.call(&mut store, (&[0xd800, 0xff00],))?.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 Ok(()) 816 } 817 818 #[tokio::test] 819 async fn async_reentrance() -> Result<()> { 820 _ = env_logger::try_init(); 821 822 let component = r#" 823 (component 824 (core module $shim 825 (import "" "task.return" (func $task-return (param i32))) 826 (table (export "funcs") 1 1 funcref) 827 (func (export "export") (param i32) (result i32) 828 (call_indirect (i32.const 0) (local.get 0)) 829 ) 830 (func (export "callback") (param i32 i32 i32) (result i32) unreachable) 831 ) 832 (core func $task-return (canon task.return (result u32))) 833 (core instance $shim (instantiate $shim 834 (with "" (instance (export "task.return" (func $task-return)))) 835 )) 836 (func $shim-export (param "p1" u32) (result u32) 837 (canon lift (core func $shim "export") async (callback (func $shim "callback"))) 838 ) 839 840 (component $inner 841 (import "import" (func $import (param "p1" u32) (result u32))) 842 (core module $libc (memory (export "memory") 1)) 843 (core instance $libc (instantiate $libc)) 844 (core func $import (canon lower (func $import) async (memory $libc "memory"))) 845 846 (core module $m 847 (import "libc" "memory" (memory 1)) 848 (import "" "import" (func $import (param i32 i32) (result i32))) 849 (import "" "task.return" (func $task-return (param i32))) 850 (func (export "export") (param i32) (result i32) 851 (i32.store offset=0 (i32.const 1200) (local.get 0)) 852 (call $import (i32.const 1200) (i32.const 1204)) 853 drop 854 (call $task-return (i32.load offset=0 (i32.const 1204))) 855 i32.const 0 856 ) 857 (func (export "callback") (param i32 i32 i32) (result i32) unreachable) 858 ) 859 (core type $task-return-type (func (param i32))) 860 (core func $task-return (canon task.return (result u32))) 861 (core instance $i (instantiate $m 862 (with "" (instance 863 (export "task.return" (func $task-return)) 864 (export "import" (func $import)) 865 )) 866 (with "libc" (instance $libc)) 867 )) 868 (func (export "export") (param "p1" u32) (result u32) 869 (canon lift (core func $i "export") async (callback (func $i "callback"))) 870 ) 871 ) 872 (instance $inner (instantiate $inner (with "import" (func $shim-export)))) 873 874 (core module $libc (memory (export "memory") 1)) 875 (core instance $libc (instantiate $libc)) 876 (core func $inner-export (canon lower (func $inner "export") async (memory $libc "memory"))) 877 878 (core module $donut 879 (import "" "funcs" (table 1 1 funcref)) 880 (import "libc" "memory" (memory 1)) 881 (import "" "import" (func $import (param i32 i32) (result i32))) 882 (import "" "task.return" (func $task-return (param i32))) 883 (func $host-export (export "export") (param i32) (result i32) 884 (i32.store offset=0 (i32.const 1200) (local.get 0)) 885 (call $import (i32.const 1200) (i32.const 1204)) 886 drop 887 (call $task-return (i32.load offset=0 (i32.const 1204))) 888 i32.const 0 889 ) 890 (func $guest-export (export "guest-export") (param i32) (result i32) unreachable) 891 (func (export "callback") (param i32 i32 i32) (result i32) unreachable) 892 (func $start 893 (table.set (i32.const 0) (ref.func $guest-export)) 894 ) 895 (start $start) 896 ) 897 898 (core instance $donut (instantiate $donut 899 (with "" (instance 900 (export "task.return" (func $task-return)) 901 (export "import" (func $inner-export)) 902 (export "funcs" (table $shim "funcs")) 903 )) 904 (with "libc" (instance $libc)) 905 )) 906 (func (export "export") (param "p1" u32) (result u32) 907 (canon lift (core func $donut "export") async (callback (func $donut "callback"))) 908 ) 909 )"#; 910 911 let mut config = Config::new(); 912 config.wasm_component_model_async(true); 913 config.async_support(true); 914 let engine = &Engine::new(&config)?; 915 let component = Component::new(&engine, component)?; 916 let mut store = Store::new(&engine, ()); 917 918 let instance = Linker::new(&engine) 919 .instantiate_async(&mut store, &component) 920 .await?; 921 let func = instance.get_typed_func::<(u32,), (u32,)>(&mut store, "export")?; 922 let message = "cannot enter component instance"; 923 match instance 924 .run_concurrent(&mut store, async move |accessor| { 925 func.call_concurrent(accessor, (42,)).await 926 }) 927 .await 928 { 929 Ok(_) => panic!(), 930 Err(e) => assert!( 931 format!("{e:?}").contains(message), 932 "expected `{message}`; got `{e:?}`" 933 ), 934 } 935 936 Ok(()) 937 } 938 939 #[tokio::test] 940 async fn missing_task_return_call_stackless() -> Result<()> { 941 task_return_trap( 942 r#"(component 943 (core module $m 944 (import "" "task.return" (func $task-return)) 945 (func (export "foo") (result i32) 946 i32.const 0 947 ) 948 (func (export "callback") (param i32 i32 i32) (result i32) unreachable) 949 ) 950 (core func $task-return (canon task.return)) 951 (core instance $i (instantiate $m 952 (with "" (instance (export "task.return" (func $task-return)))) 953 )) 954 (func (export "foo") (canon lift (core func $i "foo") async (callback (func $i "callback")))) 955 )"#, 956 "wasm trap: async-lifted export failed to produce a result", 957 ) 958 .await 959 } 960 961 #[tokio::test] 962 async fn missing_task_return_call_stackful() -> Result<()> { 963 task_return_trap( 964 r#"(component 965 (core module $m 966 (import "" "task.return" (func $task-return)) 967 (func (export "foo")) 968 ) 969 (core func $task-return (canon task.return)) 970 (core instance $i (instantiate $m 971 (with "" (instance (export "task.return" (func $task-return)))) 972 )) 973 (func (export "foo") (canon lift (core func $i "foo") async)) 974 )"#, 975 "wasm trap: async-lifted export failed to produce a result", 976 ) 977 .await 978 } 979 980 #[tokio::test] 981 async fn task_return_type_mismatch() -> Result<()> { 982 task_return_trap( 983 r#"(component 984 (core module $m 985 (import "" "task.return" (func $task-return (param i32))) 986 (func (export "foo") (call $task-return (i32.const 42))) 987 ) 988 (core func $task-return (canon task.return (result u32))) 989 (core instance $i (instantiate $m 990 (with "" (instance (export "task.return" (func $task-return)))) 991 )) 992 (func (export "foo") (canon lift (core func $i "foo") async)) 993 )"#, 994 "invalid `task.return` signature and/or options for current task", 995 ) 996 .await 997 } 998 999 #[tokio::test] 1000 async fn task_return_memory_mismatch() -> Result<()> { 1001 task_return_trap( 1002 r#"(component 1003 (core module $libc (memory (export "memory") 1)) 1004 (core instance $libc (instantiate $libc)) 1005 (core module $m 1006 (import "" "task.return" (func $task-return)) 1007 (func (export "foo") (call $task-return)) 1008 ) 1009 (core func $task-return (canon task.return (memory $libc "memory"))) 1010 (core instance $i (instantiate $m 1011 (with "" (instance (export "task.return" (func $task-return)))) 1012 )) 1013 (func (export "foo") (canon lift (core func $i "foo") async)) 1014 )"#, 1015 "invalid `task.return` signature and/or options for current task", 1016 ) 1017 .await 1018 } 1019 1020 #[tokio::test] 1021 async fn task_return_string_encoding_mismatch() -> Result<()> { 1022 task_return_trap( 1023 r#"(component 1024 (core module $m 1025 (import "" "task.return" (func $task-return)) 1026 (func (export "foo") (call $task-return)) 1027 ) 1028 (core func $task-return (canon task.return string-encoding=utf16)) 1029 (core instance $i (instantiate $m 1030 (with "" (instance (export "task.return" (func $task-return)))) 1031 )) 1032 (func (export "foo") (canon lift (core func $i "foo") async)) 1033 )"#, 1034 "invalid `task.return` signature and/or options for current task", 1035 ) 1036 .await 1037 } 1038 1039 async fn task_return_trap(component: &str, substring: &str) -> Result<()> { 1040 let mut config = Config::new(); 1041 config.wasm_component_model_async(true); 1042 config.wasm_component_model_async_stackful(true); 1043 config.async_support(true); 1044 let engine = &Engine::new(&config)?; 1045 let component = Component::new(&engine, component)?; 1046 let mut store = Store::new(&engine, ()); 1047 1048 let instance = Linker::new(&engine) 1049 .instantiate_async(&mut store, &component) 1050 .await?; 1051 1052 let func = instance.get_typed_func::<(), ()>(&mut store, "foo")?; 1053 match instance 1054 .run_concurrent(&mut store, async move |accessor| { 1055 func.call_concurrent(accessor, ()).await 1056 }) 1057 .await 1058 { 1059 Ok(_) => panic!(), 1060 Err(e) => { 1061 assert!( 1062 format!("{e:?}").contains(substring), 1063 "could not find `{substring}` in `{e:?}`" 1064 ) 1065 } 1066 } 1067 1068 Ok(()) 1069 } 1070 1071 #[tokio::test] 1072 async fn many_parameters() -> Result<()> { 1073 test_many_parameters(false, false).await 1074 } 1075 1076 #[tokio::test] 1077 async fn many_parameters_concurrent() -> Result<()> { 1078 test_many_parameters(false, true).await 1079 } 1080 1081 #[tokio::test] 1082 async fn many_parameters_dynamic() -> Result<()> { 1083 test_many_parameters(true, false).await 1084 } 1085 1086 #[tokio::test] 1087 async fn many_parameters_dynamic_concurrent() -> Result<()> { 1088 test_many_parameters(true, true).await 1089 } 1090 1091 async fn test_many_parameters(dynamic: bool, concurrent: bool) -> Result<()> { 1092 let (body, async_opts) = if concurrent { 1093 ( 1094 r#" 1095 (call $task-return 1096 (i32.const 0) 1097 (i32.mul 1098 (memory.size) 1099 (i32.const 65536) 1100 ) 1101 (local.get 0) 1102 ) 1103 1104 (i32.const 0) 1105 "#, 1106 r#"async (callback (func $i "callback"))"#, 1107 ) 1108 } else { 1109 ( 1110 r#" 1111 (local $base i32) 1112 1113 ;; Allocate space for the return 1114 (local.set $base 1115 (call $realloc 1116 (i32.const 0) 1117 (i32.const 0) 1118 (i32.const 4) 1119 (i32.const 12))) 1120 1121 ;; Store the pointer/length of the entire linear memory 1122 ;; so we have access to everything. 1123 (i32.store offset=0 1124 (local.get $base) 1125 (i32.const 0)) 1126 (i32.store offset=4 1127 (local.get $base) 1128 (i32.mul 1129 (memory.size) 1130 (i32.const 65536))) 1131 1132 ;; And also store our pointer parameter 1133 (i32.store offset=8 1134 (local.get $base) 1135 (local.get 0)) 1136 1137 (local.get $base) 1138 "#, 1139 "", 1140 ) 1141 }; 1142 1143 let component = format!( 1144 r#"(component 1145 (core module $libc 1146 (memory (export "memory") 1) 1147 1148 {REALLOC_AND_FREE} 1149 ) 1150 (core instance $libc (instantiate $libc)) 1151 (core module $m 1152 (import "libc" "memory" (memory 1)) 1153 (import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32))) 1154 (import "" "task.return" (func $task-return (param i32 i32 i32))) 1155 (func (export "foo") (param i32) (result i32) 1156 {body} 1157 ) 1158 (func (export "callback") (param i32 i32 i32) (result i32) unreachable) 1159 ) 1160 (type $tuple (tuple (list u8) u32)) 1161 (core func $task-return (canon task.return 1162 (result $tuple) 1163 (memory $libc "memory") 1164 )) 1165 (core instance $i (instantiate $m 1166 (with "" (instance (export "task.return" (func $task-return)))) 1167 (with "libc" (instance $libc)) 1168 )) 1169 1170 (type $t (func 1171 (param "p1" s8) ;; offset 0, size 1 1172 (param "p2" u64) ;; offset 8, size 8 1173 (param "p3" float32) ;; offset 16, size 4 1174 (param "p4" u8) ;; offset 20, size 1 1175 (param "p5" s16) ;; offset 22, size 2 1176 (param "p6" string) ;; offset 24, size 8 1177 (param "p7" (list u32)) ;; offset 32, size 8 1178 (param "p8" bool) ;; offset 40, size 1 1179 (param "p9" bool) ;; offset 41, size 1 1180 (param "p0" char) ;; offset 44, size 4 1181 (param "pa" (list bool)) ;; offset 48, size 8 1182 (param "pb" (list char)) ;; offset 56, size 8 1183 (param "pc" (list string)) ;; offset 64, size 8 1184 1185 (result $tuple) 1186 )) 1187 (func (export "many-param") (type $t) 1188 (canon lift 1189 (core func $i "foo") 1190 (memory $libc "memory") 1191 (realloc (func $libc "realloc")) 1192 {async_opts} 1193 ) 1194 ) 1195 )"# 1196 ); 1197 1198 let mut config = Config::new(); 1199 config.wasm_component_model_async(true); 1200 config.async_support(true); 1201 let engine = &Engine::new(&config)?; 1202 let component = Component::new(&engine, component)?; 1203 let mut store = Store::new(&engine, ()); 1204 1205 let instance = Linker::new(&engine) 1206 .instantiate_async(&mut store, &component) 1207 .await?; 1208 1209 let input = ( 1210 -100, 1211 u64::MAX / 2, 1212 f32::from_bits(CANON_32BIT_NAN | 1), 1213 38, 1214 18831, 1215 "this is the first string", 1216 [1, 2, 3, 4, 5, 6, 7, 8].as_slice(), 1217 true, 1218 false, 1219 '', 1220 [false, true, false, true, true].as_slice(), 1221 ['', '', '', '', ''].as_slice(), 1222 [ 1223 "the quick", 1224 "brown fox", 1225 "was too lazy", 1226 "to jump over the dog", 1227 "what a demanding dog", 1228 ] 1229 .as_slice(), 1230 ); 1231 1232 let (memory, pointer) = if dynamic { 1233 let input = vec![ 1234 Val::S8(input.0), 1235 Val::U64(input.1), 1236 Val::Float32(input.2), 1237 Val::U8(input.3), 1238 Val::S16(input.4), 1239 Val::String(input.5.into()), 1240 Val::List(input.6.iter().copied().map(Val::U32).collect()), 1241 Val::Bool(input.7), 1242 Val::Bool(input.8), 1243 Val::Char(input.9), 1244 Val::List(input.10.iter().copied().map(Val::Bool).collect()), 1245 Val::List(input.11.iter().copied().map(Val::Char).collect()), 1246 Val::List(input.12.iter().map(|&s| Val::String(s.into())).collect()), 1247 ]; 1248 let func = instance.get_func(&mut store, "many-param").unwrap(); 1249 1250 let mut results = vec![Val::Bool(false)]; 1251 if concurrent { 1252 instance 1253 .run_concurrent(&mut store, async |store| { 1254 func.call_concurrent(store, &input, &mut results).await 1255 }) 1256 .await??; 1257 } else { 1258 func.call_async(&mut store, &input, &mut results).await?; 1259 }; 1260 let mut results = results.into_iter(); 1261 let Some(Val::Tuple(results)) = results.next() else { 1262 panic!() 1263 }; 1264 let mut results = results.into_iter(); 1265 let Some(Val::List(memory)) = results.next() else { 1266 panic!() 1267 }; 1268 let Some(Val::U32(pointer)) = results.next() else { 1269 panic!() 1270 }; 1271 ( 1272 memory 1273 .into_iter() 1274 .map(|v| if let Val::U8(v) = v { v } else { panic!() }) 1275 .collect(), 1276 pointer, 1277 ) 1278 } else { 1279 let func = instance.get_typed_func::<( 1280 i8, 1281 u64, 1282 f32, 1283 u8, 1284 i16, 1285 &str, 1286 &[u32], 1287 bool, 1288 bool, 1289 char, 1290 &[bool], 1291 &[char], 1292 &[&str], 1293 ), ((Vec<u8>, u32),)>(&mut store, "many-param")?; 1294 1295 if concurrent { 1296 instance 1297 .run_concurrent(&mut store, async move |accessor| { 1298 func.call_concurrent(accessor, input).await 1299 }) 1300 .await?? 1301 .0 1302 } else { 1303 func.call_async(&mut store, input).await?.0 1304 } 1305 }; 1306 let memory = &memory[..]; 1307 1308 let mut actual = &memory[pointer as usize..][..72]; 1309 assert_eq!(i8::from_le_bytes(*actual.take_n::<1>()), input.0); 1310 actual.skip::<7>(); 1311 assert_eq!(u64::from_le_bytes(*actual.take_n::<8>()), input.1); 1312 assert_eq!( 1313 u32::from_le_bytes(*actual.take_n::<4>()), 1314 CANON_32BIT_NAN | 1 1315 ); 1316 assert_eq!(u8::from_le_bytes(*actual.take_n::<1>()), input.3); 1317 actual.skip::<1>(); 1318 assert_eq!(i16::from_le_bytes(*actual.take_n::<2>()), input.4); 1319 assert_eq!(actual.ptr_len(memory, 1), input.5.as_bytes()); 1320 let mut mem = actual.ptr_len(memory, 4); 1321 for expected in input.6.iter() { 1322 assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected); 1323 } 1324 assert!(mem.is_empty()); 1325 assert_eq!(actual.take_n::<1>(), &[input.7 as u8]); 1326 assert_eq!(actual.take_n::<1>(), &[input.8 as u8]); 1327 actual.skip::<2>(); 1328 assert_eq!(u32::from_le_bytes(*actual.take_n::<4>()), input.9 as u32); 1329 1330 // (list bool) 1331 mem = actual.ptr_len(memory, 1); 1332 for expected in input.10.iter() { 1333 assert_eq!(mem.take_n::<1>(), &[*expected as u8]); 1334 } 1335 assert!(mem.is_empty()); 1336 1337 // (list char) 1338 mem = actual.ptr_len(memory, 4); 1339 for expected in input.11.iter() { 1340 assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected as u32); 1341 } 1342 assert!(mem.is_empty()); 1343 1344 // (list string) 1345 mem = actual.ptr_len(memory, 8); 1346 for expected in input.12.iter() { 1347 let actual = mem.ptr_len(memory, 1); 1348 assert_eq!(actual, expected.as_bytes()); 1349 } 1350 assert!(mem.is_empty()); 1351 assert!(actual.is_empty()); 1352 1353 Ok(()) 1354 } 1355 1356 #[tokio::test] 1357 async fn many_results() -> Result<()> { 1358 test_many_results(false, false).await 1359 } 1360 1361 #[tokio::test] 1362 async fn many_results_concurrent() -> Result<()> { 1363 test_many_results(false, true).await 1364 } 1365 1366 #[tokio::test] 1367 async fn many_results_dynamic() -> Result<()> { 1368 test_many_results(true, false).await 1369 } 1370 1371 #[tokio::test] 1372 async fn many_results_dynamic_concurrent() -> Result<()> { 1373 test_many_results(true, true).await 1374 } 1375 1376 async fn test_many_results(dynamic: bool, concurrent: bool) -> Result<()> { 1377 let (ret, async_opts) = if concurrent { 1378 ( 1379 r#" 1380 call $task-return 1381 i32.const 0 1382 "#, 1383 r#"async (callback (func $i "callback"))"#, 1384 ) 1385 } else { 1386 ("", "") 1387 }; 1388 1389 let my_nan = CANON_32BIT_NAN | 1; 1390 1391 let component = format!( 1392 r#"(component 1393 (core module $libc 1394 (memory (export "memory") 1) 1395 1396 {REALLOC_AND_FREE} 1397 ) 1398 (core instance $libc (instantiate $libc)) 1399 (core module $m 1400 (import "libc" "memory" (memory 1)) 1401 (import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32))) 1402 (import "" "task.return" (func $task-return (param i32))) 1403 (func (export "foo") (result i32) 1404 (local $base i32) 1405 (local $string i32) 1406 (local $list i32) 1407 1408 (local.set $base 1409 (call $realloc 1410 (i32.const 0) 1411 (i32.const 0) 1412 (i32.const 8) 1413 (i32.const 72))) 1414 1415 (i32.store8 offset=0 1416 (local.get $base) 1417 (i32.const -100)) 1418 1419 (i64.store offset=8 1420 (local.get $base) 1421 (i64.const 9223372036854775807)) 1422 1423 (f32.store offset=16 1424 (local.get $base) 1425 (f32.reinterpret_i32 (i32.const {my_nan}))) 1426 1427 (i32.store8 offset=20 1428 (local.get $base) 1429 (i32.const 38)) 1430 1431 (i32.store16 offset=22 1432 (local.get $base) 1433 (i32.const 18831)) 1434 1435 (local.set $string 1436 (call $realloc 1437 (i32.const 0) 1438 (i32.const 0) 1439 (i32.const 1) 1440 (i32.const 6))) 1441 1442 (i32.store8 offset=0 1443 (local.get $string) 1444 (i32.const 97)) ;; 'a' 1445 (i32.store8 offset=1 1446 (local.get $string) 1447 (i32.const 98)) ;; 'b' 1448 (i32.store8 offset=2 1449 (local.get $string) 1450 (i32.const 99)) ;; 'c' 1451 (i32.store8 offset=3 1452 (local.get $string) 1453 (i32.const 100)) ;; 'd' 1454 (i32.store8 offset=4 1455 (local.get $string) 1456 (i32.const 101)) ;; 'e' 1457 (i32.store8 offset=5 1458 (local.get $string) 1459 (i32.const 102)) ;; 'f' 1460 1461 (i32.store offset=24 1462 (local.get $base) 1463 (local.get $string)) 1464 1465 (i32.store offset=28 1466 (local.get $base) 1467 (i32.const 2)) 1468 1469 (local.set $list 1470 (call $realloc 1471 (i32.const 0) 1472 (i32.const 0) 1473 (i32.const 4) 1474 (i32.const 32))) 1475 1476 (i32.store offset=0 1477 (local.get $list) 1478 (i32.const 1)) 1479 (i32.store offset=4 1480 (local.get $list) 1481 (i32.const 2)) 1482 (i32.store offset=8 1483 (local.get $list) 1484 (i32.const 3)) 1485 (i32.store offset=12 1486 (local.get $list) 1487 (i32.const 4)) 1488 (i32.store offset=16 1489 (local.get $list) 1490 (i32.const 5)) 1491 (i32.store offset=20 1492 (local.get $list) 1493 (i32.const 6)) 1494 (i32.store offset=24 1495 (local.get $list) 1496 (i32.const 7)) 1497 (i32.store offset=28 1498 (local.get $list) 1499 (i32.const 8)) 1500 1501 (i32.store offset=32 1502 (local.get $base) 1503 (local.get $list)) 1504 1505 (i32.store offset=36 1506 (local.get $base) 1507 (i32.const 8)) 1508 1509 (i32.store8 offset=40 1510 (local.get $base) 1511 (i32.const 1)) 1512 1513 (i32.store8 offset=41 1514 (local.get $base) 1515 (i32.const 0)) 1516 1517 (i32.store offset=44 1518 (local.get $base) 1519 (i32.const 128681)) ;; '' 1520 1521 (local.set $list 1522 (call $realloc 1523 (i32.const 0) 1524 (i32.const 0) 1525 (i32.const 1) 1526 (i32.const 5))) 1527 1528 (i32.store8 offset=0 1529 (local.get $list) 1530 (i32.const 0)) 1531 (i32.store8 offset=1 1532 (local.get $list) 1533 (i32.const 1)) 1534 (i32.store8 offset=2 1535 (local.get $list) 1536 (i32.const 0)) 1537 (i32.store8 offset=3 1538 (local.get $list) 1539 (i32.const 1)) 1540 (i32.store8 offset=4 1541 (local.get $list) 1542 (i32.const 1)) 1543 1544 (i32.store offset=48 1545 (local.get $base) 1546 (local.get $list)) 1547 1548 (i32.store offset=52 1549 (local.get $base) 1550 (i32.const 5)) 1551 1552 (local.set $list 1553 (call $realloc 1554 (i32.const 0) 1555 (i32.const 0) 1556 (i32.const 4) 1557 (i32.const 20))) 1558 1559 (i32.store offset=0 1560 (local.get $list) 1561 (i32.const 127820)) ;; '' 1562 (i32.store offset=4 1563 (local.get $list) 1564 (i32.const 129360)) ;; '' 1565 (i32.store offset=8 1566 (local.get $list) 1567 (i32.const 127831)) ;; '' 1568 (i32.store offset=12 1569 (local.get $list) 1570 (i32.const 127833)) ;; '' 1571 (i32.store offset=16 1572 (local.get $list) 1573 (i32.const 127841)) ;; '' 1574 1575 (i32.store offset=56 1576 (local.get $base) 1577 (local.get $list)) 1578 1579 (i32.store offset=60 1580 (local.get $base) 1581 (i32.const 5)) 1582 1583 (local.set $list 1584 (call $realloc 1585 (i32.const 0) 1586 (i32.const 0) 1587 (i32.const 4) 1588 (i32.const 16))) 1589 1590 (i32.store offset=0 1591 (local.get $list) 1592 (i32.add (local.get $string) (i32.const 2))) 1593 (i32.store offset=4 1594 (local.get $list) 1595 (i32.const 2)) 1596 (i32.store offset=8 1597 (local.get $list) 1598 (i32.add (local.get $string) (i32.const 4))) 1599 (i32.store offset=12 1600 (local.get $list) 1601 (i32.const 2)) 1602 1603 (i32.store offset=64 1604 (local.get $base) 1605 (local.get $list)) 1606 1607 (i32.store offset=68 1608 (local.get $base) 1609 (i32.const 2)) 1610 1611 local.get $base 1612 1613 {ret} 1614 ) 1615 (func (export "callback") (param i32 i32 i32) (result i32) unreachable) 1616 ) 1617 (type $tuple (tuple 1618 s8 1619 u64 1620 float32 1621 u8 1622 s16 1623 string 1624 (list u32) 1625 bool 1626 bool 1627 char 1628 (list bool) 1629 (list char) 1630 (list string) 1631 )) 1632 (core func $task-return (canon task.return 1633 (result $tuple) 1634 (memory $libc "memory") 1635 )) 1636 (core instance $i (instantiate $m 1637 (with "" (instance (export "task.return" (func $task-return)))) 1638 (with "libc" (instance $libc)) 1639 )) 1640 1641 (type $t (func (result $tuple))) 1642 (func (export "many-results") (type $t) 1643 (canon lift 1644 (core func $i "foo") 1645 (memory $libc "memory") 1646 (realloc (func $libc "realloc")) 1647 {async_opts} 1648 ) 1649 ) 1650 )"# 1651 ); 1652 1653 let mut config = Config::new(); 1654 config.wasm_component_model_async(true); 1655 config.async_support(true); 1656 let engine = &Engine::new(&config)?; 1657 let component = Component::new(&engine, component)?; 1658 let mut store = Store::new(&engine, ()); 1659 1660 let instance = Linker::new(&engine) 1661 .instantiate_async(&mut store, &component) 1662 .await?; 1663 1664 let expected = ( 1665 -100i8, 1666 u64::MAX / 2, 1667 f32::from_bits(CANON_32BIT_NAN | 1), 1668 38u8, 1669 18831i16, 1670 "ab".to_string(), 1671 vec![1u32, 2, 3, 4, 5, 6, 7, 8], 1672 true, 1673 false, 1674 '', 1675 vec![false, true, false, true, true], 1676 vec!['', '', '', '', ''], 1677 vec!["cd".to_string(), "ef".to_string()], 1678 ); 1679 1680 let actual = if dynamic { 1681 let func = instance.get_func(&mut store, "many-results").unwrap(); 1682 1683 let mut results = vec![Val::Bool(false)]; 1684 if concurrent { 1685 instance 1686 .run_concurrent(&mut store, async |store| { 1687 func.call_concurrent(store, &[], &mut results).await 1688 }) 1689 .await??; 1690 } else { 1691 func.call_async(&mut store, &[], &mut results).await?; 1692 }; 1693 let mut results = results.into_iter(); 1694 1695 let Some(Val::Tuple(results)) = results.next() else { 1696 panic!() 1697 }; 1698 let mut results = results.into_iter(); 1699 let Some(Val::S8(p1)) = results.next() else { 1700 panic!() 1701 }; 1702 let Some(Val::U64(p2)) = results.next() else { 1703 panic!() 1704 }; 1705 let Some(Val::Float32(p3)) = results.next() else { 1706 panic!() 1707 }; 1708 let Some(Val::U8(p4)) = results.next() else { 1709 panic!() 1710 }; 1711 let Some(Val::S16(p5)) = results.next() else { 1712 panic!() 1713 }; 1714 let Some(Val::String(p6)) = results.next() else { 1715 panic!() 1716 }; 1717 let Some(Val::List(p7)) = results.next() else { 1718 panic!() 1719 }; 1720 let p7 = p7 1721 .into_iter() 1722 .map(|v| if let Val::U32(v) = v { v } else { panic!() }) 1723 .collect(); 1724 let Some(Val::Bool(p8)) = results.next() else { 1725 panic!() 1726 }; 1727 let Some(Val::Bool(p9)) = results.next() else { 1728 panic!() 1729 }; 1730 let Some(Val::Char(p0)) = results.next() else { 1731 panic!() 1732 }; 1733 let Some(Val::List(pa)) = results.next() else { 1734 panic!() 1735 }; 1736 let pa = pa 1737 .into_iter() 1738 .map(|v| if let Val::Bool(v) = v { v } else { panic!() }) 1739 .collect(); 1740 let Some(Val::List(pb)) = results.next() else { 1741 panic!() 1742 }; 1743 let pb = pb 1744 .into_iter() 1745 .map(|v| if let Val::Char(v) = v { v } else { panic!() }) 1746 .collect(); 1747 let Some(Val::List(pc)) = results.next() else { 1748 panic!() 1749 }; 1750 let pc = pc 1751 .into_iter() 1752 .map(|v| if let Val::String(v) = v { v } else { panic!() }) 1753 .collect(); 1754 1755 (p1, p2, p3, p4, p5, p6, p7, p8, p9, p0, pa, pb, pc) 1756 } else { 1757 let func = instance.get_typed_func::<(), (( 1758 i8, 1759 u64, 1760 f32, 1761 u8, 1762 i16, 1763 String, 1764 Vec<u32>, 1765 bool, 1766 bool, 1767 char, 1768 Vec<bool>, 1769 Vec<char>, 1770 Vec<String>, 1771 ),)>(&mut store, "many-results")?; 1772 1773 if concurrent { 1774 instance 1775 .run_concurrent(&mut store, async move |accessor| { 1776 func.call_concurrent(accessor, ()).await 1777 }) 1778 .await?? 1779 .0 1780 } else { 1781 func.call_async(&mut store, ()).await?.0 1782 } 1783 }; 1784 1785 assert_eq!(expected.0, actual.0); 1786 assert_eq!(expected.1, actual.1); 1787 assert!(expected.2.is_nan()); 1788 assert!(actual.2.is_nan()); 1789 assert_eq!(expected.3, actual.3); 1790 assert_eq!(expected.4, actual.4); 1791 assert_eq!(expected.5, actual.5); 1792 assert_eq!(expected.6, actual.6); 1793 assert_eq!(expected.7, actual.7); 1794 assert_eq!(expected.8, actual.8); 1795 assert_eq!(expected.9, actual.9); 1796 assert_eq!(expected.10, actual.10); 1797 assert_eq!(expected.11, actual.11); 1798 assert_eq!(expected.12, actual.12); 1799 1800 Ok(()) 1801 } 1802 1803 #[test] 1804 fn some_traps() -> Result<()> { 1805 let middle_of_memory = (i32::MAX / 2) & (!0xff); 1806 let component = format!( 1807 r#"(component 1808 (core module $m 1809 (memory (export "memory") 1) 1810 (func (export "take-many") (param i32)) 1811 (func (export "take-list") (param i32 i32)) 1812 1813 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 1814 unreachable) 1815 ) 1816 (core instance $i (instantiate $m)) 1817 1818 (func (export "take-list-unreachable") (param "a" (list u8)) 1819 (canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc"))) 1820 ) 1821 (func (export "take-string-unreachable") (param "a" string) 1822 (canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc"))) 1823 ) 1824 1825 (type $t (func 1826 (param "s1" string) 1827 (param "s2" string) 1828 (param "s3" string) 1829 (param "s4" string) 1830 (param "s5" string) 1831 (param "s6" string) 1832 (param "s7" string) 1833 (param "s8" string) 1834 (param "s9" string) 1835 (param "s10" string) 1836 )) 1837 (func (export "take-many-unreachable") (type $t) 1838 (canon lift (core func $i "take-many") (memory $i "memory") (realloc (func $i "realloc"))) 1839 ) 1840 1841 (core module $m2 1842 (memory (export "memory") 1) 1843 (func (export "take-many") (param i32)) 1844 (func (export "take-list") (param i32 i32)) 1845 1846 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 1847 i32.const {middle_of_memory}) 1848 ) 1849 (core instance $i2 (instantiate $m2)) 1850 1851 (func (export "take-list-base-oob") (param "a" (list u8)) 1852 (canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc"))) 1853 ) 1854 (func (export "take-string-base-oob") (param "a" string) 1855 (canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc"))) 1856 ) 1857 (func (export "take-many-base-oob") (type $t) 1858 (canon lift (core func $i2 "take-many") (memory $i2 "memory") (realloc (func $i2 "realloc"))) 1859 ) 1860 1861 (core module $m3 1862 (memory (export "memory") 1) 1863 (func (export "take-many") (param i32)) 1864 (func (export "take-list") (param i32 i32)) 1865 1866 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 1867 i32.const 65532) 1868 ) 1869 (core instance $i3 (instantiate $m3)) 1870 1871 (func (export "take-list-end-oob") (param "a" (list u8)) 1872 (canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc"))) 1873 ) 1874 (func (export "take-string-end-oob") (param "a" string) 1875 (canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc"))) 1876 ) 1877 (func (export "take-many-end-oob") (type $t) 1878 (canon lift (core func $i3 "take-many") (memory $i3 "memory") (realloc (func $i3 "realloc"))) 1879 ) 1880 1881 (core module $m4 1882 (memory (export "memory") 1) 1883 (func (export "take-many") (param i32)) 1884 1885 (global $cnt (mut i32) (i32.const 0)) 1886 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 1887 global.get $cnt 1888 if (result i32) 1889 i32.const 100000 1890 else 1891 i32.const 1 1892 global.set $cnt 1893 i32.const 0 1894 end 1895 ) 1896 ) 1897 (core instance $i4 (instantiate $m4)) 1898 1899 (func (export "take-many-second-oob") (type $t) 1900 (canon lift (core func $i4 "take-many") (memory $i4 "memory") (realloc (func $i4 "realloc"))) 1901 ) 1902 )"# 1903 ); 1904 1905 let engine = super::engine(); 1906 let component = Component::new(&engine, component)?; 1907 let mut store = Store::new(&engine, ()); 1908 let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component); 1909 1910 // This should fail when calling the allocator function for the argument 1911 let err = instance(&mut store)? 1912 .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-unreachable")? 1913 .call(&mut store, (&[],)) 1914 .unwrap_err() 1915 .downcast::<Trap>()?; 1916 assert_eq!(err, Trap::UnreachableCodeReached); 1917 1918 // This should fail when calling the allocator function for the argument 1919 let err = instance(&mut store)? 1920 .get_typed_func::<(&str,), ()>(&mut store, "take-string-unreachable")? 1921 .call(&mut store, ("",)) 1922 .unwrap_err() 1923 .downcast::<Trap>()?; 1924 assert_eq!(err, Trap::UnreachableCodeReached); 1925 1926 // This should fail when calling the allocator function for the space 1927 // to store the arguments (before arguments are even lowered) 1928 let err = instance(&mut store)? 1929 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>( 1930 &mut store, 1931 "take-many-unreachable", 1932 )? 1933 .call(&mut store, ("", "", "", "", "", "", "", "", "", "")) 1934 .unwrap_err() 1935 .downcast::<Trap>()?; 1936 assert_eq!(err, Trap::UnreachableCodeReached); 1937 1938 // Assert that when the base pointer returned by malloc is out of bounds 1939 // that errors are reported as such. Both empty and lists with contents 1940 // should all be invalid here. 1941 // 1942 // FIXME(WebAssembly/component-model#32) confirm the semantics here are 1943 // what's desired. 1944 #[track_caller] 1945 fn assert_oob(err: &anyhow::Error) { 1946 assert!( 1947 err.to_string() 1948 .contains("realloc return: beyond end of memory"), 1949 "{err:?}", 1950 ); 1951 } 1952 let err = instance(&mut store)? 1953 .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-base-oob")? 1954 .call(&mut store, (&[],)) 1955 .unwrap_err(); 1956 assert_oob(&err); 1957 let err = instance(&mut store)? 1958 .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-base-oob")? 1959 .call(&mut store, (&[1],)) 1960 .unwrap_err(); 1961 assert_oob(&err); 1962 let err = instance(&mut store)? 1963 .get_typed_func::<(&str,), ()>(&mut store, "take-string-base-oob")? 1964 .call(&mut store, ("",)) 1965 .unwrap_err(); 1966 assert_oob(&err); 1967 let err = instance(&mut store)? 1968 .get_typed_func::<(&str,), ()>(&mut store, "take-string-base-oob")? 1969 .call(&mut store, ("x",)) 1970 .unwrap_err(); 1971 assert_oob(&err); 1972 let err = instance(&mut store)? 1973 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>( 1974 &mut store, 1975 "take-many-base-oob", 1976 )? 1977 .call(&mut store, ("", "", "", "", "", "", "", "", "", "")) 1978 .unwrap_err(); 1979 assert_oob(&err); 1980 1981 // Test here that when the returned pointer from malloc is one byte from the 1982 // end of memory that empty things are fine, but larger things are not. 1983 1984 instance(&mut store)? 1985 .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")? 1986 .call_and_post_return(&mut store, (&[],))?; 1987 instance(&mut store)? 1988 .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")? 1989 .call_and_post_return(&mut store, (&[1, 2, 3, 4],))?; 1990 let err = instance(&mut store)? 1991 .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")? 1992 .call(&mut store, (&[1, 2, 3, 4, 5],)) 1993 .unwrap_err(); 1994 assert_oob(&err); 1995 instance(&mut store)? 1996 .get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")? 1997 .call_and_post_return(&mut store, ("",))?; 1998 instance(&mut store)? 1999 .get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")? 2000 .call_and_post_return(&mut store, ("abcd",))?; 2001 let err = instance(&mut store)? 2002 .get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")? 2003 .call(&mut store, ("abcde",)) 2004 .unwrap_err(); 2005 assert_oob(&err); 2006 let err = instance(&mut store)? 2007 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>( 2008 &mut store, 2009 "take-many-end-oob", 2010 )? 2011 .call(&mut store, ("", "", "", "", "", "", "", "", "", "")) 2012 .unwrap_err(); 2013 assert_oob(&err); 2014 2015 // For this function the first allocation, the space to store all the 2016 // arguments, is in-bounds but then all further allocations, such as for 2017 // each individual string, are all out of bounds. 2018 let err = instance(&mut store)? 2019 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>( 2020 &mut store, 2021 "take-many-second-oob", 2022 )? 2023 .call(&mut store, ("", "", "", "", "", "", "", "", "", "")) 2024 .unwrap_err(); 2025 assert_oob(&err); 2026 let err = instance(&mut store)? 2027 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>( 2028 &mut store, 2029 "take-many-second-oob", 2030 )? 2031 .call(&mut store, ("", "", "", "", "", "", "", "", "", "x")) 2032 .unwrap_err(); 2033 assert_oob(&err); 2034 Ok(()) 2035 } 2036 2037 #[test] 2038 fn char_bool_memory() -> Result<()> { 2039 let component = format!( 2040 r#"(component 2041 (core module $m 2042 (memory (export "memory") 1) 2043 (func (export "ret-tuple") (param i32 i32) (result i32) 2044 (local $base i32) 2045 2046 ;; Allocate space for the return 2047 (local.set $base 2048 (call $realloc 2049 (i32.const 0) 2050 (i32.const 0) 2051 (i32.const 4) 2052 (i32.const 8))) 2053 2054 ;; store the boolean 2055 (i32.store offset=0 2056 (local.get $base) 2057 (local.get 0)) 2058 2059 ;; store the char 2060 (i32.store offset=4 2061 (local.get $base) 2062 (local.get 1)) 2063 2064 (local.get $base) 2065 ) 2066 2067 {REALLOC_AND_FREE} 2068 ) 2069 (core instance $i (instantiate $m)) 2070 2071 (func (export "ret-tuple") (param "a" u32) (param "b" u32) (result (tuple bool char)) 2072 (canon lift (core func $i "ret-tuple") 2073 (memory $i "memory") 2074 (realloc (func $i "realloc"))) 2075 ) 2076 )"# 2077 ); 2078 2079 let engine = super::engine(); 2080 let component = Component::new(&engine, component)?; 2081 let mut store = Store::new(&engine, ()); 2082 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 2083 let func = instance.get_typed_func::<(u32, u32), ((bool, char),)>(&mut store, "ret-tuple")?; 2084 2085 let (ret,) = func.call(&mut store, (0, 'a' as u32))?; 2086 assert_eq!(ret, (false, 'a')); 2087 func.post_return(&mut store)?; 2088 2089 let (ret,) = func.call(&mut store, (1, '' as u32))?; 2090 assert_eq!(ret, (true, '')); 2091 func.post_return(&mut store)?; 2092 2093 let (ret,) = func.call(&mut store, (2, 'a' as u32))?; 2094 assert_eq!(ret, (true, 'a')); 2095 func.post_return(&mut store)?; 2096 2097 assert!(func.call(&mut store, (0, 0xd800)).is_err()); 2098 2099 Ok(()) 2100 } 2101 2102 #[test] 2103 fn string_list_oob() -> Result<()> { 2104 let component = format!( 2105 r#"(component 2106 (core module $m 2107 (memory (export "memory") 1) 2108 (func (export "ret-list") (result i32) 2109 (local $base i32) 2110 2111 ;; Allocate space for the return 2112 (local.set $base 2113 (call $realloc 2114 (i32.const 0) 2115 (i32.const 0) 2116 (i32.const 4) 2117 (i32.const 8))) 2118 2119 (i32.store offset=0 2120 (local.get $base) 2121 (i32.const 100000)) 2122 (i32.store offset=4 2123 (local.get $base) 2124 (i32.const 1)) 2125 2126 (local.get $base) 2127 ) 2128 2129 {REALLOC_AND_FREE} 2130 ) 2131 (core instance $i (instantiate $m)) 2132 2133 (func (export "ret-list-u8") (result (list u8)) 2134 (canon lift (core func $i "ret-list") 2135 (memory $i "memory") 2136 (realloc (func $i "realloc")) 2137 ) 2138 ) 2139 (func (export "ret-string") (result string) 2140 (canon lift (core func $i "ret-list") 2141 (memory $i "memory") 2142 (realloc (func $i "realloc")) 2143 ) 2144 ) 2145 )"# 2146 ); 2147 2148 let engine = super::engine(); 2149 let component = Component::new(&engine, component)?; 2150 let mut store = Store::new(&engine, ()); 2151 let ret_list_u8 = Linker::new(&engine) 2152 .instantiate(&mut store, &component)? 2153 .get_typed_func::<(), (WasmList<u8>,)>(&mut store, "ret-list-u8")?; 2154 let ret_string = Linker::new(&engine) 2155 .instantiate(&mut store, &component)? 2156 .get_typed_func::<(), (WasmStr,)>(&mut store, "ret-string")?; 2157 2158 let err = ret_list_u8.call(&mut store, ()).err().unwrap(); 2159 assert!(err.to_string().contains("out of bounds"), "{}", err); 2160 2161 let err = ret_string.call(&mut store, ()).err().unwrap(); 2162 assert!(err.to_string().contains("out of bounds"), "{}", err); 2163 2164 Ok(()) 2165 } 2166 2167 #[test] 2168 fn tuples() -> Result<()> { 2169 let component = format!( 2170 r#"(component 2171 (core module $m 2172 (memory (export "memory") 1) 2173 (func (export "foo") 2174 (param i32 f64 i32) 2175 (result i32) 2176 2177 local.get 0 2178 i32.const 0 2179 i32.ne 2180 if unreachable end 2181 2182 local.get 1 2183 f64.const 1 2184 f64.ne 2185 if unreachable end 2186 2187 local.get 2 2188 i32.const 2 2189 i32.ne 2190 if unreachable end 2191 2192 i32.const 3 2193 ) 2194 ) 2195 (core instance $i (instantiate $m)) 2196 2197 (func (export "foo") 2198 (param "a" (tuple s32 float64)) 2199 (param "b" (tuple s8)) 2200 (result (tuple u16)) 2201 (canon lift (core func $i "foo")) 2202 ) 2203 )"# 2204 ); 2205 2206 let engine = super::engine(); 2207 let component = Component::new(&engine, component)?; 2208 let mut store = Store::new(&engine, ()); 2209 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 2210 let foo = instance.get_typed_func::<((i32, f64), (i8,)), ((u16,),)>(&mut store, "foo")?; 2211 assert_eq!(foo.call(&mut store, ((0, 1.0), (2,)))?, ((3,),)); 2212 2213 Ok(()) 2214 } 2215 2216 #[test] 2217 fn option() -> Result<()> { 2218 let component = format!( 2219 r#"(component 2220 (core module $m 2221 (memory (export "memory") 1) 2222 (func (export "pass1") (param i32 i32) (result i32) 2223 (local $base i32) 2224 (local.set $base 2225 (call $realloc 2226 (i32.const 0) 2227 (i32.const 0) 2228 (i32.const 4) 2229 (i32.const 8))) 2230 2231 (i32.store offset=0 2232 (local.get $base) 2233 (local.get 0)) 2234 (i32.store offset=4 2235 (local.get $base) 2236 (local.get 1)) 2237 2238 (local.get $base) 2239 ) 2240 (func (export "pass2") (param i32 i32 i32) (result i32) 2241 (local $base i32) 2242 (local.set $base 2243 (call $realloc 2244 (i32.const 0) 2245 (i32.const 0) 2246 (i32.const 4) 2247 (i32.const 12))) 2248 2249 (i32.store offset=0 2250 (local.get $base) 2251 (local.get 0)) 2252 (i32.store offset=4 2253 (local.get $base) 2254 (local.get 1)) 2255 (i32.store offset=8 2256 (local.get $base) 2257 (local.get 2)) 2258 2259 (local.get $base) 2260 ) 2261 2262 {REALLOC_AND_FREE} 2263 ) 2264 (core instance $i (instantiate $m)) 2265 2266 (func (export "option-u8-to-tuple") (param "a" (option u8)) (result (tuple u32 u32)) 2267 (canon lift (core func $i "pass1") (memory $i "memory")) 2268 ) 2269 (func (export "option-u32-to-tuple") (param "a" (option u32)) (result (tuple u32 u32)) 2270 (canon lift (core func $i "pass1") (memory $i "memory")) 2271 ) 2272 (func (export "option-string-to-tuple") (param "a" (option string)) (result (tuple u32 string)) 2273 (canon lift 2274 (core func $i "pass2") 2275 (memory $i "memory") 2276 (realloc (func $i "realloc")) 2277 ) 2278 ) 2279 (func (export "to-option-u8") (param "a" u32) (param "b" u32) (result (option u8)) 2280 (canon lift (core func $i "pass1") (memory $i "memory")) 2281 ) 2282 (func (export "to-option-u32") (param "a" u32) (param "b" u32) (result (option u32)) 2283 (canon lift 2284 (core func $i "pass1") 2285 (memory $i "memory") 2286 ) 2287 ) 2288 (func (export "to-option-string") (param "a" u32) (param "b" string) (result (option string)) 2289 (canon lift 2290 (core func $i "pass2") 2291 (memory $i "memory") 2292 (realloc (func $i "realloc")) 2293 ) 2294 ) 2295 )"# 2296 ); 2297 2298 let engine = super::engine(); 2299 let component = Component::new(&engine, component)?; 2300 let mut store = Store::new(&engine, ()); 2301 let linker = Linker::new(&engine); 2302 let instance = linker.instantiate(&mut store, &component)?; 2303 2304 let option_u8_to_tuple = instance 2305 .get_typed_func::<(Option<u8>,), ((u32, u32),)>(&mut store, "option-u8-to-tuple")?; 2306 assert_eq!(option_u8_to_tuple.call(&mut store, (None,))?, ((0, 0),)); 2307 option_u8_to_tuple.post_return(&mut store)?; 2308 assert_eq!(option_u8_to_tuple.call(&mut store, (Some(0),))?, ((1, 0),)); 2309 option_u8_to_tuple.post_return(&mut store)?; 2310 assert_eq!( 2311 option_u8_to_tuple.call(&mut store, (Some(100),))?, 2312 ((1, 100),) 2313 ); 2314 option_u8_to_tuple.post_return(&mut store)?; 2315 2316 let option_u32_to_tuple = instance 2317 .get_typed_func::<(Option<u32>,), ((u32, u32),)>(&mut store, "option-u32-to-tuple")?; 2318 assert_eq!(option_u32_to_tuple.call(&mut store, (None,))?, ((0, 0),)); 2319 option_u32_to_tuple.post_return(&mut store)?; 2320 assert_eq!(option_u32_to_tuple.call(&mut store, (Some(0),))?, ((1, 0),)); 2321 option_u32_to_tuple.post_return(&mut store)?; 2322 assert_eq!( 2323 option_u32_to_tuple.call(&mut store, (Some(100),))?, 2324 ((1, 100),) 2325 ); 2326 option_u32_to_tuple.post_return(&mut store)?; 2327 2328 let option_string_to_tuple = instance.get_typed_func::<(Option<&str>,), ((u32, WasmStr),)>( 2329 &mut store, 2330 "option-string-to-tuple", 2331 )?; 2332 let ((a, b),) = option_string_to_tuple.call(&mut store, (None,))?; 2333 assert_eq!(a, 0); 2334 assert_eq!(b.to_str(&store)?, ""); 2335 option_string_to_tuple.post_return(&mut store)?; 2336 let ((a, b),) = option_string_to_tuple.call(&mut store, (Some(""),))?; 2337 assert_eq!(a, 1); 2338 assert_eq!(b.to_str(&store)?, ""); 2339 option_string_to_tuple.post_return(&mut store)?; 2340 let ((a, b),) = option_string_to_tuple.call(&mut store, (Some("hello"),))?; 2341 assert_eq!(a, 1); 2342 assert_eq!(b.to_str(&store)?, "hello"); 2343 option_string_to_tuple.post_return(&mut store)?; 2344 2345 let instance = linker.instantiate(&mut store, &component)?; 2346 let to_option_u8 = 2347 instance.get_typed_func::<(u32, u32), (Option<u8>,)>(&mut store, "to-option-u8")?; 2348 assert_eq!(to_option_u8.call(&mut store, (0x00_00, 0))?, (None,)); 2349 to_option_u8.post_return(&mut store)?; 2350 assert_eq!(to_option_u8.call(&mut store, (0x00_01, 0))?, (Some(0),)); 2351 to_option_u8.post_return(&mut store)?; 2352 assert_eq!(to_option_u8.call(&mut store, (0xfd_01, 0))?, (Some(0xfd),)); 2353 to_option_u8.post_return(&mut store)?; 2354 assert!(to_option_u8.call(&mut store, (0x00_02, 0)).is_err()); 2355 2356 let instance = linker.instantiate(&mut store, &component)?; 2357 let to_option_u32 = 2358 instance.get_typed_func::<(u32, u32), (Option<u32>,)>(&mut store, "to-option-u32")?; 2359 assert_eq!(to_option_u32.call(&mut store, (0, 0))?, (None,)); 2360 to_option_u32.post_return(&mut store)?; 2361 assert_eq!(to_option_u32.call(&mut store, (1, 0))?, (Some(0),)); 2362 to_option_u32.post_return(&mut store)?; 2363 assert_eq!( 2364 to_option_u32.call(&mut store, (1, 0x1234fead))?, 2365 (Some(0x1234fead),) 2366 ); 2367 to_option_u32.post_return(&mut store)?; 2368 assert!(to_option_u32.call(&mut store, (2, 0)).is_err()); 2369 2370 let instance = linker.instantiate(&mut store, &component)?; 2371 let to_option_string = instance 2372 .get_typed_func::<(u32, &str), (Option<WasmStr>,)>(&mut store, "to-option-string")?; 2373 let ret = to_option_string.call(&mut store, (0, ""))?.0; 2374 assert!(ret.is_none()); 2375 to_option_string.post_return(&mut store)?; 2376 let ret = to_option_string.call(&mut store, (1, ""))?.0; 2377 assert_eq!(ret.unwrap().to_str(&store)?, ""); 2378 to_option_string.post_return(&mut store)?; 2379 let ret = to_option_string.call(&mut store, (1, "cheesecake"))?.0; 2380 assert_eq!(ret.unwrap().to_str(&store)?, "cheesecake"); 2381 to_option_string.post_return(&mut store)?; 2382 assert!(to_option_string.call(&mut store, (2, "")).is_err()); 2383 2384 Ok(()) 2385 } 2386 2387 #[test] 2388 fn expected() -> Result<()> { 2389 let component = format!( 2390 r#"(component 2391 (core module $m 2392 (memory (export "memory") 1) 2393 (func (export "pass0") (param i32) (result i32) 2394 local.get 0 2395 ) 2396 (func (export "pass1") (param i32 i32) (result i32) 2397 (local $base i32) 2398 (local.set $base 2399 (call $realloc 2400 (i32.const 0) 2401 (i32.const 0) 2402 (i32.const 4) 2403 (i32.const 8))) 2404 2405 (i32.store offset=0 2406 (local.get $base) 2407 (local.get 0)) 2408 (i32.store offset=4 2409 (local.get $base) 2410 (local.get 1)) 2411 2412 (local.get $base) 2413 ) 2414 (func (export "pass2") (param i32 i32 i32) (result i32) 2415 (local $base i32) 2416 (local.set $base 2417 (call $realloc 2418 (i32.const 0) 2419 (i32.const 0) 2420 (i32.const 4) 2421 (i32.const 12))) 2422 2423 (i32.store offset=0 2424 (local.get $base) 2425 (local.get 0)) 2426 (i32.store offset=4 2427 (local.get $base) 2428 (local.get 1)) 2429 (i32.store offset=8 2430 (local.get $base) 2431 (local.get 2)) 2432 2433 (local.get $base) 2434 ) 2435 2436 {REALLOC_AND_FREE} 2437 ) 2438 (core instance $i (instantiate $m)) 2439 2440 (func (export "take-expected-unit") (param "a" (result)) (result u32) 2441 (canon lift (core func $i "pass0")) 2442 ) 2443 (func (export "take-expected-u8-f32") (param "a" (result u8 (error float32))) (result (tuple u32 u32)) 2444 (canon lift (core func $i "pass1") (memory $i "memory")) 2445 ) 2446 (type $list (list u8)) 2447 (func (export "take-expected-string") (param "a" (result string (error $list))) (result (tuple u32 string)) 2448 (canon lift 2449 (core func $i "pass2") 2450 (memory $i "memory") 2451 (realloc (func $i "realloc")) 2452 ) 2453 ) 2454 (func (export "to-expected-unit") (param "a" u32) (result (result)) 2455 (canon lift (core func $i "pass0")) 2456 ) 2457 (func (export "to-expected-s16-f32") (param "a" u32) (param "b" u32) (result (result s16 (error float32))) 2458 (canon lift 2459 (core func $i "pass1") 2460 (memory $i "memory") 2461 (realloc (func $i "realloc")) 2462 ) 2463 ) 2464 )"# 2465 ); 2466 2467 let engine = super::engine(); 2468 let component = Component::new(&engine, component)?; 2469 let mut store = Store::new(&engine, ()); 2470 let linker = Linker::new(&engine); 2471 let instance = linker.instantiate(&mut store, &component)?; 2472 let take_expected_unit = 2473 instance.get_typed_func::<(Result<(), ()>,), (u32,)>(&mut store, "take-expected-unit")?; 2474 assert_eq!(take_expected_unit.call(&mut store, (Ok(()),))?, (0,)); 2475 take_expected_unit.post_return(&mut store)?; 2476 assert_eq!(take_expected_unit.call(&mut store, (Err(()),))?, (1,)); 2477 take_expected_unit.post_return(&mut store)?; 2478 2479 let take_expected_u8_f32 = instance 2480 .get_typed_func::<(Result<u8, f32>,), ((u32, u32),)>(&mut store, "take-expected-u8-f32")?; 2481 assert_eq!(take_expected_u8_f32.call(&mut store, (Ok(1),))?, ((0, 1),)); 2482 take_expected_u8_f32.post_return(&mut store)?; 2483 assert_eq!( 2484 take_expected_u8_f32.call(&mut store, (Err(2.0),))?, 2485 ((1, 2.0f32.to_bits()),) 2486 ); 2487 take_expected_u8_f32.post_return(&mut store)?; 2488 2489 let take_expected_string = instance 2490 .get_typed_func::<(Result<&str, &[u8]>,), ((u32, WasmStr),)>( 2491 &mut store, 2492 "take-expected-string", 2493 )?; 2494 let ((a, b),) = take_expected_string.call(&mut store, (Ok("hello"),))?; 2495 assert_eq!(a, 0); 2496 assert_eq!(b.to_str(&store)?, "hello"); 2497 take_expected_string.post_return(&mut store)?; 2498 let ((a, b),) = take_expected_string.call(&mut store, (Err(b"goodbye"),))?; 2499 assert_eq!(a, 1); 2500 assert_eq!(b.to_str(&store)?, "goodbye"); 2501 take_expected_string.post_return(&mut store)?; 2502 2503 let instance = linker.instantiate(&mut store, &component)?; 2504 let to_expected_unit = 2505 instance.get_typed_func::<(u32,), (Result<(), ()>,)>(&mut store, "to-expected-unit")?; 2506 assert_eq!(to_expected_unit.call(&mut store, (0,))?, (Ok(()),)); 2507 to_expected_unit.post_return(&mut store)?; 2508 assert_eq!(to_expected_unit.call(&mut store, (1,))?, (Err(()),)); 2509 to_expected_unit.post_return(&mut store)?; 2510 let err = to_expected_unit.call(&mut store, (2,)).unwrap_err(); 2511 assert!(err.to_string().contains("invalid expected"), "{}", err); 2512 2513 let instance = linker.instantiate(&mut store, &component)?; 2514 let to_expected_s16_f32 = instance 2515 .get_typed_func::<(u32, u32), (Result<i16, f32>,)>(&mut store, "to-expected-s16-f32")?; 2516 assert_eq!(to_expected_s16_f32.call(&mut store, (0, 0))?, (Ok(0),)); 2517 to_expected_s16_f32.post_return(&mut store)?; 2518 assert_eq!(to_expected_s16_f32.call(&mut store, (0, 100))?, (Ok(100),)); 2519 to_expected_s16_f32.post_return(&mut store)?; 2520 assert_eq!( 2521 to_expected_s16_f32.call(&mut store, (1, 1.0f32.to_bits()))?, 2522 (Err(1.0),) 2523 ); 2524 to_expected_s16_f32.post_return(&mut store)?; 2525 let ret = to_expected_s16_f32 2526 .call(&mut store, (1, CANON_32BIT_NAN | 1))? 2527 .0; 2528 assert_eq!(ret.unwrap_err().to_bits(), CANON_32BIT_NAN | 1); 2529 to_expected_s16_f32.post_return(&mut store)?; 2530 assert!(to_expected_s16_f32.call(&mut store, (2, 0)).is_err()); 2531 2532 Ok(()) 2533 } 2534 2535 #[test] 2536 fn fancy_list() -> Result<()> { 2537 let component = format!( 2538 r#"(component 2539 (core module $m 2540 (memory (export "memory") 1) 2541 (func (export "take") (param i32 i32) (result i32) 2542 (local $base i32) 2543 (local.set $base 2544 (call $realloc 2545 (i32.const 0) 2546 (i32.const 0) 2547 (i32.const 4) 2548 (i32.const 16))) 2549 2550 (i32.store offset=0 2551 (local.get $base) 2552 (local.get 0)) 2553 (i32.store offset=4 2554 (local.get $base) 2555 (local.get 1)) 2556 (i32.store offset=8 2557 (local.get $base) 2558 (i32.const 0)) 2559 (i32.store offset=12 2560 (local.get $base) 2561 (i32.mul 2562 (memory.size) 2563 (i32.const 65536))) 2564 2565 (local.get $base) 2566 ) 2567 2568 {REALLOC_AND_FREE} 2569 ) 2570 (core instance $i (instantiate $m)) 2571 2572 (type $a (option u8)) 2573 (type $b (result (error string))) 2574 (type $input (list (tuple $a $b))) 2575 (func (export "take") 2576 (param "a" $input) 2577 (result (tuple u32 u32 (list u8))) 2578 (canon lift 2579 (core func $i "take") 2580 (memory $i "memory") 2581 (realloc (func $i "realloc")) 2582 ) 2583 ) 2584 )"# 2585 ); 2586 2587 let engine = super::engine(); 2588 let component = Component::new(&engine, component)?; 2589 let mut store = Store::new(&engine, ()); 2590 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 2591 2592 let func = instance 2593 .get_typed_func::<(&[(Option<u8>, Result<(), &str>)],), ((u32, u32, WasmList<u8>),)>( 2594 &mut store, "take", 2595 )?; 2596 2597 let input = [ 2598 (None, Ok(())), 2599 (Some(2), Err("hello there")), 2600 (Some(200), Err("general kenobi")), 2601 ]; 2602 let ((ptr, len, list),) = func.call(&mut store, (&input,))?; 2603 let memory = list.as_le_slice(&store); 2604 let ptr = usize::try_from(ptr).unwrap(); 2605 let len = usize::try_from(len).unwrap(); 2606 let mut array = &memory[ptr..][..len * 16]; 2607 2608 for (a, b) in input.iter() { 2609 match a { 2610 Some(val) => { 2611 assert_eq!(*array.take_n::<2>(), [1, *val]); 2612 } 2613 None => { 2614 assert_eq!(*array.take_n::<1>(), [0]); 2615 array.skip::<1>(); 2616 } 2617 } 2618 array.skip::<2>(); 2619 match b { 2620 Ok(()) => { 2621 assert_eq!(*array.take_n::<1>(), [0]); 2622 array.skip::<11>(); 2623 } 2624 Err(s) => { 2625 assert_eq!(*array.take_n::<1>(), [1]); 2626 array.skip::<3>(); 2627 assert_eq!(array.ptr_len(memory, 1), s.as_bytes()); 2628 } 2629 } 2630 } 2631 assert!(array.is_empty()); 2632 2633 Ok(()) 2634 } 2635 2636 trait SliceExt<'a> { 2637 fn take_n<const N: usize>(&mut self) -> &'a [u8; N]; 2638 2639 fn skip<const N: usize>(&mut self) { 2640 self.take_n::<N>(); 2641 } 2642 2643 fn ptr_len<'b>(&mut self, all_memory: &'b [u8], size: usize) -> &'b [u8] { 2644 let ptr = u32::from_le_bytes(*self.take_n::<4>()); 2645 let len = u32::from_le_bytes(*self.take_n::<4>()); 2646 let ptr = usize::try_from(ptr).unwrap(); 2647 let len = usize::try_from(len).unwrap(); 2648 &all_memory[ptr..][..len * size] 2649 } 2650 } 2651 2652 impl<'a> SliceExt<'a> for &'a [u8] { 2653 fn take_n<const N: usize>(&mut self) -> &'a [u8; N] { 2654 let (a, b) = self.split_at(N); 2655 *self = b; 2656 a.try_into().unwrap() 2657 } 2658 } 2659 2660 #[test] 2661 fn invalid_alignment() -> Result<()> { 2662 let component = format!( 2663 r#"(component 2664 (core module $m 2665 (memory (export "memory") 1) 2666 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 2667 i32.const 1) 2668 2669 (func (export "take-i32") (param i32)) 2670 (func (export "ret-1") (result i32) i32.const 1) 2671 (func (export "ret-unaligned-list") (result i32) 2672 (i32.store offset=0 (i32.const 8) (i32.const 1)) 2673 (i32.store offset=4 (i32.const 8) (i32.const 1)) 2674 i32.const 8) 2675 ) 2676 (core instance $i (instantiate $m)) 2677 2678 (func (export "many-params") 2679 (param "s1" string) (param "s2" string) (param "s3" string) (param "s4" string) 2680 (param "s5" string) (param "s6" string) (param "s7" string) (param "s8" string) 2681 (param "s9" string) (param "s10" string) (param "s11" string) (param "s12" string) 2682 (canon lift 2683 (core func $i "take-i32") 2684 (memory $i "memory") 2685 (realloc (func $i "realloc")) 2686 ) 2687 ) 2688 (func (export "string-ret") (result string) 2689 (canon lift 2690 (core func $i "ret-1") 2691 (memory $i "memory") 2692 (realloc (func $i "realloc")) 2693 ) 2694 ) 2695 (func (export "list-u32-ret") (result (list u32)) 2696 (canon lift 2697 (core func $i "ret-unaligned-list") 2698 (memory $i "memory") 2699 (realloc (func $i "realloc")) 2700 ) 2701 ) 2702 )"# 2703 ); 2704 2705 let engine = super::engine(); 2706 let component = Component::new(&engine, component)?; 2707 let mut store = Store::new(&engine, ()); 2708 let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component); 2709 2710 let err = instance(&mut store)? 2711 .get_typed_func::<( 2712 &str, 2713 &str, 2714 &str, 2715 &str, 2716 &str, 2717 &str, 2718 &str, 2719 &str, 2720 &str, 2721 &str, 2722 &str, 2723 &str, 2724 ), ()>(&mut store, "many-params")? 2725 .call(&mut store, ("", "", "", "", "", "", "", "", "", "", "", "")) 2726 .unwrap_err(); 2727 assert!( 2728 err.to_string() 2729 .contains("realloc return: result not aligned"), 2730 "{}", 2731 err 2732 ); 2733 2734 let err = instance(&mut store)? 2735 .get_typed_func::<(), (WasmStr,)>(&mut store, "string-ret")? 2736 .call(&mut store, ()) 2737 .err() 2738 .unwrap(); 2739 assert!( 2740 err.to_string().contains("return pointer not aligned"), 2741 "{}", 2742 err 2743 ); 2744 2745 let err = instance(&mut store)? 2746 .get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32-ret")? 2747 .call(&mut store, ()) 2748 .err() 2749 .unwrap(); 2750 assert!( 2751 err.to_string().contains("list pointer is not aligned"), 2752 "{}", 2753 err 2754 ); 2755 2756 Ok(()) 2757 } 2758 2759 #[test] 2760 fn drop_component_still_works() -> Result<()> { 2761 let component = r#" 2762 (component 2763 (import "f" (func $f)) 2764 2765 (core func $f_lower 2766 (canon lower (func $f)) 2767 ) 2768 (core module $m 2769 (import "" "" (func $f)) 2770 2771 (func $f2 2772 call $f 2773 call $f 2774 ) 2775 2776 (export "f" (func $f2)) 2777 ) 2778 (core instance $i (instantiate $m 2779 (with "" (instance 2780 (export "" (func $f_lower)) 2781 )) 2782 )) 2783 (func (export "g") 2784 (canon lift 2785 (core func $i "f") 2786 ) 2787 ) 2788 ) 2789 "#; 2790 2791 let (mut store, instance) = { 2792 let engine = super::engine(); 2793 let component = Component::new(&engine, component)?; 2794 let mut store = Store::new(&engine, 0); 2795 let mut linker = Linker::new(&engine); 2796 linker.root().func_wrap( 2797 "f", 2798 |mut store: StoreContextMut<'_, u32>, _: ()| -> Result<()> { 2799 *store.data_mut() += 1; 2800 Ok(()) 2801 }, 2802 )?; 2803 let instance = linker.instantiate(&mut store, &component)?; 2804 (store, instance) 2805 }; 2806 2807 let f = instance.get_typed_func::<(), ()>(&mut store, "g")?; 2808 assert_eq!(*store.data(), 0); 2809 f.call(&mut store, ())?; 2810 assert_eq!(*store.data(), 2); 2811 2812 Ok(()) 2813 } 2814 2815 #[test] 2816 fn raw_slice_of_various_types() -> Result<()> { 2817 let component = r#" 2818 (component 2819 (core module $m 2820 (memory (export "memory") 1) 2821 2822 (func (export "list8") (result i32) 2823 (call $setup_list (i32.const 16)) 2824 ) 2825 (func (export "list16") (result i32) 2826 (call $setup_list (i32.const 8)) 2827 ) 2828 (func (export "list32") (result i32) 2829 (call $setup_list (i32.const 4)) 2830 ) 2831 (func (export "list64") (result i32) 2832 (call $setup_list (i32.const 2)) 2833 ) 2834 2835 (func $setup_list (param i32) (result i32) 2836 (i32.store offset=0 (i32.const 100) (i32.const 8)) 2837 (i32.store offset=4 (i32.const 100) (local.get 0)) 2838 i32.const 100 2839 ) 2840 2841 (data (i32.const 8) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f") 2842 ) 2843 (core instance $i (instantiate $m)) 2844 (func (export "list-u8") (result (list u8)) 2845 (canon lift (core func $i "list8") (memory $i "memory")) 2846 ) 2847 (func (export "list-i8") (result (list s8)) 2848 (canon lift (core func $i "list8") (memory $i "memory")) 2849 ) 2850 (func (export "list-u16") (result (list u16)) 2851 (canon lift (core func $i "list16") (memory $i "memory")) 2852 ) 2853 (func (export "list-i16") (result (list s16)) 2854 (canon lift (core func $i "list16") (memory $i "memory")) 2855 ) 2856 (func (export "list-u32") (result (list u32)) 2857 (canon lift (core func $i "list32") (memory $i "memory")) 2858 ) 2859 (func (export "list-i32") (result (list s32)) 2860 (canon lift (core func $i "list32") (memory $i "memory")) 2861 ) 2862 (func (export "list-u64") (result (list u64)) 2863 (canon lift (core func $i "list64") (memory $i "memory")) 2864 ) 2865 (func (export "list-i64") (result (list s64)) 2866 (canon lift (core func $i "list64") (memory $i "memory")) 2867 ) 2868 ) 2869 "#; 2870 2871 let (mut store, instance) = { 2872 let engine = super::engine(); 2873 let component = Component::new(&engine, component)?; 2874 let mut store = Store::new(&engine, ()); 2875 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 2876 (store, instance) 2877 }; 2878 2879 let list = instance 2880 .get_typed_func::<(), (WasmList<u8>,)>(&mut store, "list-u8")? 2881 .call_and_post_return(&mut store, ())? 2882 .0; 2883 assert_eq!( 2884 list.as_le_slice(&store), 2885 [ 2886 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 2887 0x0e, 0x0f, 2888 ] 2889 ); 2890 let list = instance 2891 .get_typed_func::<(), (WasmList<i8>,)>(&mut store, "list-i8")? 2892 .call_and_post_return(&mut store, ())? 2893 .0; 2894 assert_eq!( 2895 list.as_le_slice(&store), 2896 [ 2897 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 2898 0x0e, 0x0f, 2899 ] 2900 ); 2901 2902 let list = instance 2903 .get_typed_func::<(), (WasmList<u16>,)>(&mut store, "list-u16")? 2904 .call_and_post_return(&mut store, ())? 2905 .0; 2906 assert_eq!( 2907 list.as_le_slice(&store), 2908 [ 2909 u16::to_le(0x01_00), 2910 u16::to_le(0x03_02), 2911 u16::to_le(0x05_04), 2912 u16::to_le(0x07_06), 2913 u16::to_le(0x09_08), 2914 u16::to_le(0x0b_0a), 2915 u16::to_le(0x0d_0c), 2916 u16::to_le(0x0f_0e), 2917 ] 2918 ); 2919 let list = instance 2920 .get_typed_func::<(), (WasmList<i16>,)>(&mut store, "list-i16")? 2921 .call_and_post_return(&mut store, ())? 2922 .0; 2923 assert_eq!( 2924 list.as_le_slice(&store), 2925 [ 2926 i16::to_le(0x01_00), 2927 i16::to_le(0x03_02), 2928 i16::to_le(0x05_04), 2929 i16::to_le(0x07_06), 2930 i16::to_le(0x09_08), 2931 i16::to_le(0x0b_0a), 2932 i16::to_le(0x0d_0c), 2933 i16::to_le(0x0f_0e), 2934 ] 2935 ); 2936 let list = instance 2937 .get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32")? 2938 .call_and_post_return(&mut store, ())? 2939 .0; 2940 assert_eq!( 2941 list.as_le_slice(&store), 2942 [ 2943 u32::to_le(0x03_02_01_00), 2944 u32::to_le(0x07_06_05_04), 2945 u32::to_le(0x0b_0a_09_08), 2946 u32::to_le(0x0f_0e_0d_0c), 2947 ] 2948 ); 2949 let list = instance 2950 .get_typed_func::<(), (WasmList<i32>,)>(&mut store, "list-i32")? 2951 .call_and_post_return(&mut store, ())? 2952 .0; 2953 assert_eq!( 2954 list.as_le_slice(&store), 2955 [ 2956 i32::to_le(0x03_02_01_00), 2957 i32::to_le(0x07_06_05_04), 2958 i32::to_le(0x0b_0a_09_08), 2959 i32::to_le(0x0f_0e_0d_0c), 2960 ] 2961 ); 2962 let list = instance 2963 .get_typed_func::<(), (WasmList<u64>,)>(&mut store, "list-u64")? 2964 .call_and_post_return(&mut store, ())? 2965 .0; 2966 assert_eq!( 2967 list.as_le_slice(&store), 2968 [ 2969 u64::to_le(0x07_06_05_04_03_02_01_00), 2970 u64::to_le(0x0f_0e_0d_0c_0b_0a_09_08), 2971 ] 2972 ); 2973 let list = instance 2974 .get_typed_func::<(), (WasmList<i64>,)>(&mut store, "list-i64")? 2975 .call_and_post_return(&mut store, ())? 2976 .0; 2977 assert_eq!( 2978 list.as_le_slice(&store), 2979 [ 2980 i64::to_le(0x07_06_05_04_03_02_01_00), 2981 i64::to_le(0x0f_0e_0d_0c_0b_0a_09_08), 2982 ] 2983 ); 2984 2985 Ok(()) 2986 } 2987 2988 #[test] 2989 fn lower_then_lift() -> Result<()> { 2990 // First test simple integers when the import/export ABI happen to line up 2991 let component = r#" 2992 (component $c 2993 (import "f" (func $f (result u32))) 2994 2995 (core func $f_lower 2996 (canon lower (func $f)) 2997 ) 2998 (func $f2 (result s32) 2999 (canon lift (core func $f_lower)) 3000 ) 3001 (export "f2" (func $f2)) 3002 ) 3003 "#; 3004 3005 let engine = super::engine(); 3006 let component = Component::new(&engine, component)?; 3007 let mut store = Store::new(&engine, ()); 3008 let mut linker = Linker::new(&engine); 3009 linker.root().func_wrap("f", |_, _: ()| Ok((2u32,)))?; 3010 let instance = linker.instantiate(&mut store, &component)?; 3011 3012 let f = instance.get_typed_func::<(), (i32,)>(&mut store, "f2")?; 3013 assert_eq!(f.call(&mut store, ())?, (2,)); 3014 3015 // First test strings when the import/export ABI happen to line up 3016 let component = format!( 3017 r#" 3018 (component $c 3019 (import "s" (func $f (param "a" string))) 3020 3021 (core module $libc 3022 (memory (export "memory") 1) 3023 {REALLOC_AND_FREE} 3024 ) 3025 (core instance $libc (instantiate $libc)) 3026 3027 (core func $f_lower 3028 (canon lower (func $f) (memory $libc "memory")) 3029 ) 3030 (func $f2 (param "a" string) 3031 (canon lift (core func $f_lower) 3032 (memory $libc "memory") 3033 (realloc (func $libc "realloc")) 3034 ) 3035 ) 3036 (export "f" (func $f2)) 3037 ) 3038 "# 3039 ); 3040 3041 let component = Component::new(&engine, component)?; 3042 let mut store = Store::new(&engine, ()); 3043 linker 3044 .root() 3045 .func_wrap("s", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| { 3046 assert_eq!(x.to_str(&store)?, "hello"); 3047 Ok(()) 3048 })?; 3049 let instance = linker.instantiate(&mut store, &component)?; 3050 3051 let f = instance.get_typed_func::<(&str,), ()>(&mut store, "f")?; 3052 f.call(&mut store, ("hello",))?; 3053 3054 // Next test "type punning" where return values are reinterpreted just 3055 // because the return ABI happens to line up. 3056 let component = format!( 3057 r#" 3058 (component $c 3059 (import "s2" (func $f (param "a" string) (result u32))) 3060 3061 (core module $libc 3062 (memory (export "memory") 1) 3063 {REALLOC_AND_FREE} 3064 ) 3065 (core instance $libc (instantiate $libc)) 3066 3067 (core func $f_lower 3068 (canon lower (func $f) (memory $libc "memory")) 3069 ) 3070 (func $f2 (param "a" string) (result string) 3071 (canon lift (core func $f_lower) 3072 (memory $libc "memory") 3073 (realloc (func $libc "realloc")) 3074 ) 3075 ) 3076 (export "f" (func $f2)) 3077 ) 3078 "# 3079 ); 3080 3081 let component = Component::new(&engine, component)?; 3082 let mut store = Store::new(&engine, ()); 3083 linker 3084 .root() 3085 .func_wrap("s2", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| { 3086 assert_eq!(x.to_str(&store)?, "hello"); 3087 Ok((u32::MAX,)) 3088 })?; 3089 let instance = linker.instantiate(&mut store, &component)?; 3090 3091 let f = instance.get_typed_func::<(&str,), (WasmStr,)>(&mut store, "f")?; 3092 let err = f.call(&mut store, ("hello",)).err().unwrap(); 3093 assert!( 3094 err.to_string().contains("return pointer not aligned"), 3095 "{}", 3096 err 3097 ); 3098 3099 Ok(()) 3100 } 3101 3102 #[test] 3103 fn errors_that_poison_instance() -> Result<()> { 3104 let component = format!( 3105 r#" 3106 (component $c 3107 (core module $m1 3108 (func (export "f1") unreachable) 3109 (func (export "f2")) 3110 ) 3111 (core instance $m1 (instantiate $m1)) 3112 (func (export "f1") (canon lift (core func $m1 "f1"))) 3113 (func (export "f2") (canon lift (core func $m1 "f2"))) 3114 3115 (core module $m2 3116 (func (export "f") (param i32 i32)) 3117 (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) 3118 (memory (export "m") 1) 3119 ) 3120 (core instance $m2 (instantiate $m2)) 3121 (func (export "f3") (param "a" string) 3122 (canon lift (core func $m2 "f") (realloc (func $m2 "r")) (memory $m2 "m")) 3123 ) 3124 3125 (core module $m3 3126 (func (export "f") (result i32) i32.const 1) 3127 (memory (export "m") 1) 3128 ) 3129 (core instance $m3 (instantiate $m3)) 3130 (func (export "f4") (result string) 3131 (canon lift (core func $m3 "f") (memory $m3 "m")) 3132 ) 3133 ) 3134 "# 3135 ); 3136 3137 let engine = super::engine(); 3138 let component = Component::new(&engine, component)?; 3139 let mut store = Store::new(&engine, ()); 3140 let linker = Linker::new(&engine); 3141 let instance = linker.instantiate(&mut store, &component)?; 3142 let f1 = instance.get_typed_func::<(), ()>(&mut store, "f1")?; 3143 let f2 = instance.get_typed_func::<(), ()>(&mut store, "f2")?; 3144 assert_unreachable(f1.call(&mut store, ())); 3145 assert_poisoned(f1.call(&mut store, ())); 3146 assert_poisoned(f2.call(&mut store, ())); 3147 3148 let instance = linker.instantiate(&mut store, &component)?; 3149 let f3 = instance.get_typed_func::<(&str,), ()>(&mut store, "f3")?; 3150 assert_unreachable(f3.call(&mut store, ("x",))); 3151 assert_poisoned(f3.call(&mut store, ("x",))); 3152 3153 let instance = linker.instantiate(&mut store, &component)?; 3154 let f4 = instance.get_typed_func::<(), (WasmStr,)>(&mut store, "f4")?; 3155 assert!(f4.call(&mut store, ()).is_err()); 3156 assert_poisoned(f4.call(&mut store, ())); 3157 3158 return Ok(()); 3159 3160 #[track_caller] 3161 fn assert_unreachable<T>(err: Result<T>) { 3162 let err = match err { 3163 Ok(_) => panic!("expected an error"), 3164 Err(e) => e, 3165 }; 3166 assert_eq!( 3167 err.downcast::<Trap>().unwrap(), 3168 Trap::UnreachableCodeReached 3169 ); 3170 } 3171 3172 #[track_caller] 3173 fn assert_poisoned<T>(err: Result<T>) { 3174 let err = match err { 3175 Ok(_) => panic!("expected an error"), 3176 Err(e) => e, 3177 }; 3178 assert_eq!( 3179 err.downcast_ref::<Trap>(), 3180 Some(&Trap::CannotEnterComponent), 3181 "{err}", 3182 ); 3183 } 3184 } 3185 3186 #[test] 3187 fn run_export_with_internal_adapter() -> Result<()> { 3188 let component = r#" 3189 (component 3190 (type $t (func (param "a" u32) (result u32))) 3191 (component $a 3192 (core module $m 3193 (func (export "add-five") (param i32) (result i32) 3194 local.get 0 3195 i32.const 5 3196 i32.add) 3197 ) 3198 (core instance $m (instantiate $m)) 3199 (func (export "add-five") (type $t) (canon lift (core func $m "add-five"))) 3200 ) 3201 (component $b 3202 (import "interface-v1" (instance $i 3203 (export "add-five" (func (type $t))))) 3204 (core module $m 3205 (func $add-five (import "interface-0.1.0" "add-five") (param i32) (result i32)) 3206 (func) ;; causes index out of bounds 3207 (func (export "run") (result i32) i32.const 0 call $add-five) 3208 ) 3209 (core func $add-five (canon lower (func $i "add-five"))) 3210 (core instance $i (instantiate 0 3211 (with "interface-0.1.0" (instance 3212 (export "add-five" (func $add-five)) 3213 )) 3214 )) 3215 (func (result u32) (canon lift (core func $i "run"))) 3216 (export "run" (func 1)) 3217 ) 3218 (instance $a (instantiate $a)) 3219 (instance $b (instantiate $b (with "interface-v1" (instance $a)))) 3220 (export "run" (func $b "run")) 3221 ) 3222 "#; 3223 let engine = super::engine(); 3224 let component = Component::new(&engine, component)?; 3225 let mut store = Store::new(&engine, ()); 3226 let linker = Linker::new(&engine); 3227 let instance = linker.instantiate(&mut store, &component)?; 3228 let run = instance.get_typed_func::<(), (u32,)>(&mut store, "run")?; 3229 assert_eq!(run.call(&mut store, ())?, (5,)); 3230 Ok(()) 3231 } 3232