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