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::{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 "a" u8) (result "b" 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 = super::engine(); 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 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, 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,) 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,) 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 "all-memory" (list u8)) 878 (result "pointer" u32) 879 )) 880 (func (export "many-param") (type $t) 881 (canon lift 882 (core func $i "foo") 883 (memory $i "memory") 884 (realloc (func $i "realloc")) 885 ) 886 ) 887 )"# 888 ); 889 890 let engine = super::engine(); 891 let component = Component::new(&engine, component)?; 892 let mut store = Store::new(&engine, ()); 893 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 894 let func = instance.get_typed_func::<( 895 i8, 896 u64, 897 f32, 898 u8, 899 i16, 900 &str, 901 &[u32], 902 bool, 903 bool, 904 char, 905 &[bool], 906 &[char], 907 &[&str], 908 ), (WasmList<u8>, u32)>(&mut store, "many-param")?; 909 910 let input = ( 911 -100, 912 u64::MAX / 2, 913 f32::from_bits(CANON_32BIT_NAN | 1), 914 38, 915 18831, 916 "this is the first string", 917 [1, 2, 3, 4, 5, 6, 7, 8].as_slice(), 918 true, 919 false, 920 '', 921 [false, true, false, true, true].as_slice(), 922 ['', '', '', '', ''].as_slice(), 923 [ 924 "the quick", 925 "brown fox", 926 "was too lazy", 927 "to jump over the dog", 928 "what a demanding dog", 929 ] 930 .as_slice(), 931 ); 932 let (memory, pointer) = func.call(&mut store, input)?; 933 let memory = memory.as_le_slice(&store); 934 935 let mut actual = &memory[pointer as usize..][..72]; 936 assert_eq!(i8::from_le_bytes(*actual.take_n::<1>()), input.0); 937 actual.skip::<7>(); 938 assert_eq!(u64::from_le_bytes(*actual.take_n::<8>()), input.1); 939 assert_eq!(u32::from_le_bytes(*actual.take_n::<4>()), CANON_32BIT_NAN); 940 assert_eq!(u8::from_le_bytes(*actual.take_n::<1>()), input.3); 941 actual.skip::<1>(); 942 assert_eq!(i16::from_le_bytes(*actual.take_n::<2>()), input.4); 943 assert_eq!(actual.ptr_len(memory, 1), input.5.as_bytes()); 944 let mut mem = actual.ptr_len(memory, 4); 945 for expected in input.6.iter() { 946 assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected); 947 } 948 assert!(mem.is_empty()); 949 assert_eq!(actual.take_n::<1>(), &[input.7 as u8]); 950 assert_eq!(actual.take_n::<1>(), &[input.8 as u8]); 951 actual.skip::<2>(); 952 assert_eq!(u32::from_le_bytes(*actual.take_n::<4>()), input.9 as u32); 953 954 // (list bool) 955 mem = actual.ptr_len(memory, 1); 956 for expected in input.10.iter() { 957 assert_eq!(mem.take_n::<1>(), &[*expected as u8]); 958 } 959 assert!(mem.is_empty()); 960 961 // (list char) 962 mem = actual.ptr_len(memory, 4); 963 for expected in input.11.iter() { 964 assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected as u32); 965 } 966 assert!(mem.is_empty()); 967 968 // (list string) 969 mem = actual.ptr_len(memory, 8); 970 for expected in input.12.iter() { 971 let actual = mem.ptr_len(memory, 1); 972 assert_eq!(actual, expected.as_bytes()); 973 } 974 assert!(mem.is_empty()); 975 assert!(actual.is_empty()); 976 977 Ok(()) 978 } 979 980 #[test] 981 fn some_traps() -> Result<()> { 982 let middle_of_memory = (i32::MAX / 2) & (!0xff); 983 let component = format!( 984 r#"(component 985 (core module $m 986 (memory (export "memory") 1) 987 (func (export "take-many") (param i32)) 988 (func (export "take-list") (param i32 i32)) 989 990 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 991 unreachable) 992 ) 993 (core instance $i (instantiate $m)) 994 995 (func (export "take-list-unreachable") (param "a" (list u8)) 996 (canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc"))) 997 ) 998 (func (export "take-string-unreachable") (param "a" string) 999 (canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc"))) 1000 ) 1001 1002 (type $t (func 1003 (param "s1" string) 1004 (param "s2" string) 1005 (param "s3" string) 1006 (param "s4" string) 1007 (param "s5" string) 1008 (param "s6" string) 1009 (param "s7" string) 1010 (param "s8" string) 1011 (param "s9" string) 1012 (param "s10" string) 1013 )) 1014 (func (export "take-many-unreachable") (type $t) 1015 (canon lift (core func $i "take-many") (memory $i "memory") (realloc (func $i "realloc"))) 1016 ) 1017 1018 (core module $m2 1019 (memory (export "memory") 1) 1020 (func (export "take-many") (param i32)) 1021 (func (export "take-list") (param i32 i32)) 1022 1023 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 1024 i32.const {middle_of_memory}) 1025 ) 1026 (core instance $i2 (instantiate $m2)) 1027 1028 (func (export "take-list-base-oob") (param "a" (list u8)) 1029 (canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc"))) 1030 ) 1031 (func (export "take-string-base-oob") (param "a" string) 1032 (canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc"))) 1033 ) 1034 (func (export "take-many-base-oob") (type $t) 1035 (canon lift (core func $i2 "take-many") (memory $i2 "memory") (realloc (func $i2 "realloc"))) 1036 ) 1037 1038 (core module $m3 1039 (memory (export "memory") 1) 1040 (func (export "take-many") (param i32)) 1041 (func (export "take-list") (param i32 i32)) 1042 1043 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 1044 i32.const 65532) 1045 ) 1046 (core instance $i3 (instantiate $m3)) 1047 1048 (func (export "take-list-end-oob") (param "a" (list u8)) 1049 (canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc"))) 1050 ) 1051 (func (export "take-string-end-oob") (param "a" string) 1052 (canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc"))) 1053 ) 1054 (func (export "take-many-end-oob") (type $t) 1055 (canon lift (core func $i3 "take-many") (memory $i3 "memory") (realloc (func $i3 "realloc"))) 1056 ) 1057 1058 (core module $m4 1059 (memory (export "memory") 1) 1060 (func (export "take-many") (param i32)) 1061 1062 (global $cnt (mut i32) (i32.const 0)) 1063 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 1064 global.get $cnt 1065 if (result i32) 1066 i32.const 100000 1067 else 1068 i32.const 1 1069 global.set $cnt 1070 i32.const 0 1071 end 1072 ) 1073 ) 1074 (core instance $i4 (instantiate $m4)) 1075 1076 (func (export "take-many-second-oob") (type $t) 1077 (canon lift (core func $i4 "take-many") (memory $i4 "memory") (realloc (func $i4 "realloc"))) 1078 ) 1079 )"# 1080 ); 1081 1082 let engine = super::engine(); 1083 let component = Component::new(&engine, component)?; 1084 let mut store = Store::new(&engine, ()); 1085 let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component); 1086 1087 // This should fail when calling the allocator function for the argument 1088 let err = instance(&mut store)? 1089 .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-unreachable")? 1090 .call(&mut store, (&[],)) 1091 .unwrap_err() 1092 .downcast::<Trap>()?; 1093 assert_eq!(err, Trap::UnreachableCodeReached); 1094 1095 // This should fail when calling the allocator function for the argument 1096 let err = instance(&mut store)? 1097 .get_typed_func::<(&str,), ()>(&mut store, "take-string-unreachable")? 1098 .call(&mut store, ("",)) 1099 .unwrap_err() 1100 .downcast::<Trap>()?; 1101 assert_eq!(err, Trap::UnreachableCodeReached); 1102 1103 // This should fail when calling the allocator function for the space 1104 // to store the arguments (before arguments are even lowered) 1105 let err = instance(&mut store)? 1106 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>( 1107 &mut store, 1108 "take-many-unreachable", 1109 )? 1110 .call(&mut store, ("", "", "", "", "", "", "", "", "", "")) 1111 .unwrap_err() 1112 .downcast::<Trap>()?; 1113 assert_eq!(err, Trap::UnreachableCodeReached); 1114 1115 // Assert that when the base pointer returned by malloc is out of bounds 1116 // that errors are reported as such. Both empty and lists with contents 1117 // should all be invalid here. 1118 // 1119 // FIXME(WebAssembly/component-model#32) confirm the semantics here are 1120 // what's desired. 1121 #[track_caller] 1122 fn assert_oob(err: &anyhow::Error) { 1123 assert!( 1124 err.to_string() 1125 .contains("realloc return: beyond end of memory"), 1126 "{:?}", 1127 err, 1128 ); 1129 } 1130 let err = instance(&mut store)? 1131 .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-base-oob")? 1132 .call(&mut store, (&[],)) 1133 .unwrap_err(); 1134 assert_oob(&err); 1135 let err = instance(&mut store)? 1136 .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-base-oob")? 1137 .call(&mut store, (&[1],)) 1138 .unwrap_err(); 1139 assert_oob(&err); 1140 let err = instance(&mut store)? 1141 .get_typed_func::<(&str,), ()>(&mut store, "take-string-base-oob")? 1142 .call(&mut store, ("",)) 1143 .unwrap_err(); 1144 assert_oob(&err); 1145 let err = instance(&mut store)? 1146 .get_typed_func::<(&str,), ()>(&mut store, "take-string-base-oob")? 1147 .call(&mut store, ("x",)) 1148 .unwrap_err(); 1149 assert_oob(&err); 1150 let err = instance(&mut store)? 1151 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>( 1152 &mut store, 1153 "take-many-base-oob", 1154 )? 1155 .call(&mut store, ("", "", "", "", "", "", "", "", "", "")) 1156 .unwrap_err(); 1157 assert_oob(&err); 1158 1159 // Test here that when the returned pointer from malloc is one byte from the 1160 // end of memory that empty things are fine, but larger things are not. 1161 1162 instance(&mut store)? 1163 .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")? 1164 .call_and_post_return(&mut store, (&[],))?; 1165 instance(&mut store)? 1166 .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")? 1167 .call_and_post_return(&mut store, (&[1, 2, 3, 4],))?; 1168 let err = instance(&mut store)? 1169 .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")? 1170 .call(&mut store, (&[1, 2, 3, 4, 5],)) 1171 .unwrap_err(); 1172 assert_oob(&err); 1173 instance(&mut store)? 1174 .get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")? 1175 .call_and_post_return(&mut store, ("",))?; 1176 instance(&mut store)? 1177 .get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")? 1178 .call_and_post_return(&mut store, ("abcd",))?; 1179 let err = instance(&mut store)? 1180 .get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")? 1181 .call(&mut store, ("abcde",)) 1182 .unwrap_err(); 1183 assert_oob(&err); 1184 let err = instance(&mut store)? 1185 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>( 1186 &mut store, 1187 "take-many-end-oob", 1188 )? 1189 .call(&mut store, ("", "", "", "", "", "", "", "", "", "")) 1190 .unwrap_err(); 1191 assert_oob(&err); 1192 1193 // For this function the first allocation, the space to store all the 1194 // arguments, is in-bounds but then all further allocations, such as for 1195 // each individual string, are all out of bounds. 1196 let err = instance(&mut store)? 1197 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>( 1198 &mut store, 1199 "take-many-second-oob", 1200 )? 1201 .call(&mut store, ("", "", "", "", "", "", "", "", "", "")) 1202 .unwrap_err(); 1203 assert_oob(&err); 1204 let err = instance(&mut store)? 1205 .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>( 1206 &mut store, 1207 "take-many-second-oob", 1208 )? 1209 .call(&mut store, ("", "", "", "", "", "", "", "", "", "x")) 1210 .unwrap_err(); 1211 assert_oob(&err); 1212 Ok(()) 1213 } 1214 1215 #[test] 1216 fn char_bool_memory() -> Result<()> { 1217 let component = format!( 1218 r#"(component 1219 (core module $m 1220 (memory (export "memory") 1) 1221 (func (export "ret-tuple") (param i32 i32) (result i32) 1222 (local $base i32) 1223 1224 ;; Allocate space for the return 1225 (local.set $base 1226 (call $realloc 1227 (i32.const 0) 1228 (i32.const 0) 1229 (i32.const 4) 1230 (i32.const 8))) 1231 1232 ;; store the boolean 1233 (i32.store offset=0 1234 (local.get $base) 1235 (local.get 0)) 1236 1237 ;; store the char 1238 (i32.store offset=4 1239 (local.get $base) 1240 (local.get 1)) 1241 1242 (local.get $base) 1243 ) 1244 1245 {REALLOC_AND_FREE} 1246 ) 1247 (core instance $i (instantiate $m)) 1248 1249 (func (export "ret-tuple") (param "a" u32) (param "b" u32) (result "c" bool) (result "d" char) 1250 (canon lift (core func $i "ret-tuple") 1251 (memory $i "memory") 1252 (realloc (func $i "realloc"))) 1253 ) 1254 )"# 1255 ); 1256 1257 let engine = super::engine(); 1258 let component = Component::new(&engine, component)?; 1259 let mut store = Store::new(&engine, ()); 1260 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 1261 let func = instance.get_typed_func::<(u32, u32), (bool, char)>(&mut store, "ret-tuple")?; 1262 1263 let ret = func.call(&mut store, (0, 'a' as u32))?; 1264 assert_eq!(ret, (false, 'a')); 1265 func.post_return(&mut store)?; 1266 1267 let ret = func.call(&mut store, (1, '' as u32))?; 1268 assert_eq!(ret, (true, '')); 1269 func.post_return(&mut store)?; 1270 1271 let ret = func.call(&mut store, (2, 'a' as u32))?; 1272 assert_eq!(ret, (true, 'a')); 1273 func.post_return(&mut store)?; 1274 1275 assert!(func.call(&mut store, (0, 0xd800)).is_err()); 1276 1277 Ok(()) 1278 } 1279 1280 #[test] 1281 fn string_list_oob() -> Result<()> { 1282 let component = format!( 1283 r#"(component 1284 (core module $m 1285 (memory (export "memory") 1) 1286 (func (export "ret-list") (result i32) 1287 (local $base i32) 1288 1289 ;; Allocate space for the return 1290 (local.set $base 1291 (call $realloc 1292 (i32.const 0) 1293 (i32.const 0) 1294 (i32.const 4) 1295 (i32.const 8))) 1296 1297 (i32.store offset=0 1298 (local.get $base) 1299 (i32.const 100000)) 1300 (i32.store offset=4 1301 (local.get $base) 1302 (i32.const 1)) 1303 1304 (local.get $base) 1305 ) 1306 1307 {REALLOC_AND_FREE} 1308 ) 1309 (core instance $i (instantiate $m)) 1310 1311 (func (export "ret-list-u8") (result (list u8)) 1312 (canon lift (core func $i "ret-list") 1313 (memory $i "memory") 1314 (realloc (func $i "realloc")) 1315 ) 1316 ) 1317 (func (export "ret-string") (result string) 1318 (canon lift (core func $i "ret-list") 1319 (memory $i "memory") 1320 (realloc (func $i "realloc")) 1321 ) 1322 ) 1323 )"# 1324 ); 1325 1326 let engine = super::engine(); 1327 let component = Component::new(&engine, component)?; 1328 let mut store = Store::new(&engine, ()); 1329 let ret_list_u8 = Linker::new(&engine) 1330 .instantiate(&mut store, &component)? 1331 .get_typed_func::<(), (WasmList<u8>,)>(&mut store, "ret-list-u8")?; 1332 let ret_string = Linker::new(&engine) 1333 .instantiate(&mut store, &component)? 1334 .get_typed_func::<(), (WasmStr,)>(&mut store, "ret-string")?; 1335 1336 let err = ret_list_u8.call(&mut store, ()).err().unwrap(); 1337 assert!(err.to_string().contains("out of bounds"), "{}", err); 1338 1339 let err = ret_string.call(&mut store, ()).err().unwrap(); 1340 assert!(err.to_string().contains("out of bounds"), "{}", err); 1341 1342 Ok(()) 1343 } 1344 1345 #[test] 1346 fn tuples() -> Result<()> { 1347 let component = format!( 1348 r#"(component 1349 (core module $m 1350 (memory (export "memory") 1) 1351 (func (export "foo") 1352 (param i32 f64 i32) 1353 (result i32) 1354 1355 local.get 0 1356 i32.const 0 1357 i32.ne 1358 if unreachable end 1359 1360 local.get 1 1361 f64.const 1 1362 f64.ne 1363 if unreachable end 1364 1365 local.get 2 1366 i32.const 2 1367 i32.ne 1368 if unreachable end 1369 1370 i32.const 3 1371 ) 1372 ) 1373 (core instance $i (instantiate $m)) 1374 1375 (func (export "foo") 1376 (param "a" (tuple s32 float64)) 1377 (param "b" (tuple s8)) 1378 (result (tuple u16)) 1379 (canon lift (core func $i "foo")) 1380 ) 1381 )"# 1382 ); 1383 1384 let engine = super::engine(); 1385 let component = Component::new(&engine, component)?; 1386 let mut store = Store::new(&engine, ()); 1387 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 1388 let foo = instance.get_typed_func::<((i32, f64), (i8,)), ((u16,),)>(&mut store, "foo")?; 1389 assert_eq!(foo.call(&mut store, ((0, 1.0), (2,)))?, ((3,),)); 1390 1391 Ok(()) 1392 } 1393 1394 #[test] 1395 fn option() -> Result<()> { 1396 let component = format!( 1397 r#"(component 1398 (core module $m 1399 (memory (export "memory") 1) 1400 (func (export "pass1") (param i32 i32) (result i32) 1401 (local $base i32) 1402 (local.set $base 1403 (call $realloc 1404 (i32.const 0) 1405 (i32.const 0) 1406 (i32.const 4) 1407 (i32.const 8))) 1408 1409 (i32.store offset=0 1410 (local.get $base) 1411 (local.get 0)) 1412 (i32.store offset=4 1413 (local.get $base) 1414 (local.get 1)) 1415 1416 (local.get $base) 1417 ) 1418 (func (export "pass2") (param i32 i32 i32) (result i32) 1419 (local $base i32) 1420 (local.set $base 1421 (call $realloc 1422 (i32.const 0) 1423 (i32.const 0) 1424 (i32.const 4) 1425 (i32.const 12))) 1426 1427 (i32.store offset=0 1428 (local.get $base) 1429 (local.get 0)) 1430 (i32.store offset=4 1431 (local.get $base) 1432 (local.get 1)) 1433 (i32.store offset=8 1434 (local.get $base) 1435 (local.get 2)) 1436 1437 (local.get $base) 1438 ) 1439 1440 {REALLOC_AND_FREE} 1441 ) 1442 (core instance $i (instantiate $m)) 1443 1444 (func (export "option-u8-to-tuple") (param "a" (option u8)) (result "a" u32) (result "b" u32) 1445 (canon lift (core func $i "pass1") (memory $i "memory")) 1446 ) 1447 (func (export "option-u32-to-tuple") (param "a" (option u32)) (result "a" u32) (result "b" u32) 1448 (canon lift (core func $i "pass1") (memory $i "memory")) 1449 ) 1450 (func (export "option-string-to-tuple") (param "a" (option string)) (result "a" u32) (result "b" string) 1451 (canon lift 1452 (core func $i "pass2") 1453 (memory $i "memory") 1454 (realloc (func $i "realloc")) 1455 ) 1456 ) 1457 (func (export "to-option-u8") (param "a" u32) (param "b" u32) (result (option u8)) 1458 (canon lift (core func $i "pass1") (memory $i "memory")) 1459 ) 1460 (func (export "to-option-u32") (param "a" u32) (param "b" u32) (result (option u32)) 1461 (canon lift 1462 (core func $i "pass1") 1463 (memory $i "memory") 1464 ) 1465 ) 1466 (func (export "to-option-string") (param "a" u32) (param "b" string) (result (option string)) 1467 (canon lift 1468 (core func $i "pass2") 1469 (memory $i "memory") 1470 (realloc (func $i "realloc")) 1471 ) 1472 ) 1473 )"# 1474 ); 1475 1476 let engine = super::engine(); 1477 let component = Component::new(&engine, component)?; 1478 let mut store = Store::new(&engine, ()); 1479 let linker = Linker::new(&engine); 1480 let instance = linker.instantiate(&mut store, &component)?; 1481 1482 let option_u8_to_tuple = 1483 instance.get_typed_func::<(Option<u8>,), (u32, u32)>(&mut store, "option-u8-to-tuple")?; 1484 assert_eq!(option_u8_to_tuple.call(&mut store, (None,))?, (0, 0)); 1485 option_u8_to_tuple.post_return(&mut store)?; 1486 assert_eq!(option_u8_to_tuple.call(&mut store, (Some(0),))?, (1, 0)); 1487 option_u8_to_tuple.post_return(&mut store)?; 1488 assert_eq!(option_u8_to_tuple.call(&mut store, (Some(100),))?, (1, 100)); 1489 option_u8_to_tuple.post_return(&mut store)?; 1490 1491 let option_u32_to_tuple = 1492 instance.get_typed_func::<(Option<u32>,), (u32, u32)>(&mut store, "option-u32-to-tuple")?; 1493 assert_eq!(option_u32_to_tuple.call(&mut store, (None,))?, (0, 0)); 1494 option_u32_to_tuple.post_return(&mut store)?; 1495 assert_eq!(option_u32_to_tuple.call(&mut store, (Some(0),))?, (1, 0)); 1496 option_u32_to_tuple.post_return(&mut store)?; 1497 assert_eq!( 1498 option_u32_to_tuple.call(&mut store, (Some(100),))?, 1499 (1, 100) 1500 ); 1501 option_u32_to_tuple.post_return(&mut store)?; 1502 1503 let option_string_to_tuple = instance 1504 .get_typed_func::<(Option<&str>,), (u32, WasmStr)>(&mut store, "option-string-to-tuple")?; 1505 let (a, b) = option_string_to_tuple.call(&mut store, (None,))?; 1506 assert_eq!(a, 0); 1507 assert_eq!(b.to_str(&store)?, ""); 1508 option_string_to_tuple.post_return(&mut store)?; 1509 let (a, b) = option_string_to_tuple.call(&mut store, (Some(""),))?; 1510 assert_eq!(a, 1); 1511 assert_eq!(b.to_str(&store)?, ""); 1512 option_string_to_tuple.post_return(&mut store)?; 1513 let (a, b) = option_string_to_tuple.call(&mut store, (Some("hello"),))?; 1514 assert_eq!(a, 1); 1515 assert_eq!(b.to_str(&store)?, "hello"); 1516 option_string_to_tuple.post_return(&mut store)?; 1517 1518 let instance = linker.instantiate(&mut store, &component)?; 1519 let to_option_u8 = 1520 instance.get_typed_func::<(u32, u32), (Option<u8>,)>(&mut store, "to-option-u8")?; 1521 assert_eq!(to_option_u8.call(&mut store, (0x00_00, 0))?, (None,)); 1522 to_option_u8.post_return(&mut store)?; 1523 assert_eq!(to_option_u8.call(&mut store, (0x00_01, 0))?, (Some(0),)); 1524 to_option_u8.post_return(&mut store)?; 1525 assert_eq!(to_option_u8.call(&mut store, (0xfd_01, 0))?, (Some(0xfd),)); 1526 to_option_u8.post_return(&mut store)?; 1527 assert!(to_option_u8.call(&mut store, (0x00_02, 0)).is_err()); 1528 1529 let instance = linker.instantiate(&mut store, &component)?; 1530 let to_option_u32 = 1531 instance.get_typed_func::<(u32, u32), (Option<u32>,)>(&mut store, "to-option-u32")?; 1532 assert_eq!(to_option_u32.call(&mut store, (0, 0))?, (None,)); 1533 to_option_u32.post_return(&mut store)?; 1534 assert_eq!(to_option_u32.call(&mut store, (1, 0))?, (Some(0),)); 1535 to_option_u32.post_return(&mut store)?; 1536 assert_eq!( 1537 to_option_u32.call(&mut store, (1, 0x1234fead))?, 1538 (Some(0x1234fead),) 1539 ); 1540 to_option_u32.post_return(&mut store)?; 1541 assert!(to_option_u32.call(&mut store, (2, 0)).is_err()); 1542 1543 let instance = linker.instantiate(&mut store, &component)?; 1544 let to_option_string = instance 1545 .get_typed_func::<(u32, &str), (Option<WasmStr>,)>(&mut store, "to-option-string")?; 1546 let ret = to_option_string.call(&mut store, (0, ""))?.0; 1547 assert!(ret.is_none()); 1548 to_option_string.post_return(&mut store)?; 1549 let ret = to_option_string.call(&mut store, (1, ""))?.0; 1550 assert_eq!(ret.unwrap().to_str(&store)?, ""); 1551 to_option_string.post_return(&mut store)?; 1552 let ret = to_option_string.call(&mut store, (1, "cheesecake"))?.0; 1553 assert_eq!(ret.unwrap().to_str(&store)?, "cheesecake"); 1554 to_option_string.post_return(&mut store)?; 1555 assert!(to_option_string.call(&mut store, (2, "")).is_err()); 1556 1557 Ok(()) 1558 } 1559 1560 #[test] 1561 fn expected() -> Result<()> { 1562 let component = format!( 1563 r#"(component 1564 (core module $m 1565 (memory (export "memory") 1) 1566 (func (export "pass0") (param i32) (result i32) 1567 local.get 0 1568 ) 1569 (func (export "pass1") (param i32 i32) (result i32) 1570 (local $base i32) 1571 (local.set $base 1572 (call $realloc 1573 (i32.const 0) 1574 (i32.const 0) 1575 (i32.const 4) 1576 (i32.const 8))) 1577 1578 (i32.store offset=0 1579 (local.get $base) 1580 (local.get 0)) 1581 (i32.store offset=4 1582 (local.get $base) 1583 (local.get 1)) 1584 1585 (local.get $base) 1586 ) 1587 (func (export "pass2") (param i32 i32 i32) (result i32) 1588 (local $base i32) 1589 (local.set $base 1590 (call $realloc 1591 (i32.const 0) 1592 (i32.const 0) 1593 (i32.const 4) 1594 (i32.const 12))) 1595 1596 (i32.store offset=0 1597 (local.get $base) 1598 (local.get 0)) 1599 (i32.store offset=4 1600 (local.get $base) 1601 (local.get 1)) 1602 (i32.store offset=8 1603 (local.get $base) 1604 (local.get 2)) 1605 1606 (local.get $base) 1607 ) 1608 1609 {REALLOC_AND_FREE} 1610 ) 1611 (core instance $i (instantiate $m)) 1612 1613 (func (export "take-expected-unit") (param "a" (result)) (result u32) 1614 (canon lift (core func $i "pass0")) 1615 ) 1616 (func (export "take-expected-u8-f32") (param "a" (result u8 (error float32))) (result "a" u32) (result "b" u32) 1617 (canon lift (core func $i "pass1") (memory $i "memory")) 1618 ) 1619 (type $list (list u8)) 1620 (func (export "take-expected-string") (param "a" (result string (error $list))) (result "a" u32) (result "b" string) 1621 (canon lift 1622 (core func $i "pass2") 1623 (memory $i "memory") 1624 (realloc (func $i "realloc")) 1625 ) 1626 ) 1627 (func (export "to-expected-unit") (param "a" u32) (result (result)) 1628 (canon lift (core func $i "pass0")) 1629 ) 1630 (func (export "to-expected-s16-f32") (param "a" u32) (param "b" u32) (result (result s16 (error float32))) 1631 (canon lift 1632 (core func $i "pass1") 1633 (memory $i "memory") 1634 (realloc (func $i "realloc")) 1635 ) 1636 ) 1637 )"# 1638 ); 1639 1640 let engine = super::engine(); 1641 let component = Component::new(&engine, component)?; 1642 let mut store = Store::new(&engine, ()); 1643 let linker = Linker::new(&engine); 1644 let instance = linker.instantiate(&mut store, &component)?; 1645 let take_expected_unit = 1646 instance.get_typed_func::<(Result<(), ()>,), (u32,)>(&mut store, "take-expected-unit")?; 1647 assert_eq!(take_expected_unit.call(&mut store, (Ok(()),))?, (0,)); 1648 take_expected_unit.post_return(&mut store)?; 1649 assert_eq!(take_expected_unit.call(&mut store, (Err(()),))?, (1,)); 1650 take_expected_unit.post_return(&mut store)?; 1651 1652 let take_expected_u8_f32 = instance 1653 .get_typed_func::<(Result<u8, f32>,), (u32, u32)>(&mut store, "take-expected-u8-f32")?; 1654 assert_eq!(take_expected_u8_f32.call(&mut store, (Ok(1),))?, (0, 1)); 1655 take_expected_u8_f32.post_return(&mut store)?; 1656 assert_eq!( 1657 take_expected_u8_f32.call(&mut store, (Err(2.0),))?, 1658 (1, 2.0f32.to_bits()) 1659 ); 1660 take_expected_u8_f32.post_return(&mut store)?; 1661 1662 let take_expected_string = instance.get_typed_func::<(Result<&str, &[u8]>,), (u32, WasmStr)>( 1663 &mut store, 1664 "take-expected-string", 1665 )?; 1666 let (a, b) = take_expected_string.call(&mut store, (Ok("hello"),))?; 1667 assert_eq!(a, 0); 1668 assert_eq!(b.to_str(&store)?, "hello"); 1669 take_expected_string.post_return(&mut store)?; 1670 let (a, b) = take_expected_string.call(&mut store, (Err(b"goodbye"),))?; 1671 assert_eq!(a, 1); 1672 assert_eq!(b.to_str(&store)?, "goodbye"); 1673 take_expected_string.post_return(&mut store)?; 1674 1675 let instance = linker.instantiate(&mut store, &component)?; 1676 let to_expected_unit = 1677 instance.get_typed_func::<(u32,), (Result<(), ()>,)>(&mut store, "to-expected-unit")?; 1678 assert_eq!(to_expected_unit.call(&mut store, (0,))?, (Ok(()),)); 1679 to_expected_unit.post_return(&mut store)?; 1680 assert_eq!(to_expected_unit.call(&mut store, (1,))?, (Err(()),)); 1681 to_expected_unit.post_return(&mut store)?; 1682 let err = to_expected_unit.call(&mut store, (2,)).unwrap_err(); 1683 assert!(err.to_string().contains("invalid expected"), "{}", err); 1684 1685 let instance = linker.instantiate(&mut store, &component)?; 1686 let to_expected_s16_f32 = instance 1687 .get_typed_func::<(u32, u32), (Result<i16, f32>,)>(&mut store, "to-expected-s16-f32")?; 1688 assert_eq!(to_expected_s16_f32.call(&mut store, (0, 0))?, (Ok(0),)); 1689 to_expected_s16_f32.post_return(&mut store)?; 1690 assert_eq!(to_expected_s16_f32.call(&mut store, (0, 100))?, (Ok(100),)); 1691 to_expected_s16_f32.post_return(&mut store)?; 1692 assert_eq!( 1693 to_expected_s16_f32.call(&mut store, (1, 1.0f32.to_bits()))?, 1694 (Err(1.0),) 1695 ); 1696 to_expected_s16_f32.post_return(&mut store)?; 1697 let ret = to_expected_s16_f32 1698 .call(&mut store, (1, CANON_32BIT_NAN | 1))? 1699 .0; 1700 assert_eq!(ret.unwrap_err().to_bits(), CANON_32BIT_NAN); 1701 to_expected_s16_f32.post_return(&mut store)?; 1702 assert!(to_expected_s16_f32.call(&mut store, (2, 0)).is_err()); 1703 1704 Ok(()) 1705 } 1706 1707 #[test] 1708 fn fancy_list() -> Result<()> { 1709 let component = format!( 1710 r#"(component 1711 (core module $m 1712 (memory (export "memory") 1) 1713 (func (export "take") (param i32 i32) (result i32) 1714 (local $base i32) 1715 (local.set $base 1716 (call $realloc 1717 (i32.const 0) 1718 (i32.const 0) 1719 (i32.const 4) 1720 (i32.const 16))) 1721 1722 (i32.store offset=0 1723 (local.get $base) 1724 (local.get 0)) 1725 (i32.store offset=4 1726 (local.get $base) 1727 (local.get 1)) 1728 (i32.store offset=8 1729 (local.get $base) 1730 (i32.const 0)) 1731 (i32.store offset=12 1732 (local.get $base) 1733 (i32.mul 1734 (memory.size) 1735 (i32.const 65536))) 1736 1737 (local.get $base) 1738 ) 1739 1740 {REALLOC_AND_FREE} 1741 ) 1742 (core instance $i (instantiate $m)) 1743 1744 (type $a (option u8)) 1745 (type $b (result (error string))) 1746 (type $input (list (tuple $a $b))) 1747 (func (export "take") 1748 (param "a" $input) 1749 (result "ptr" u32) 1750 (result "len" u32) 1751 (result "list" (list u8)) 1752 (canon lift 1753 (core func $i "take") 1754 (memory $i "memory") 1755 (realloc (func $i "realloc")) 1756 ) 1757 ) 1758 )"# 1759 ); 1760 1761 let engine = super::engine(); 1762 let component = Component::new(&engine, component)?; 1763 let mut store = Store::new(&engine, ()); 1764 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 1765 1766 let func = instance 1767 .get_typed_func::<(&[(Option<u8>, Result<(), &str>)],), (u32, u32, WasmList<u8>)>( 1768 &mut store, "take", 1769 )?; 1770 1771 let input = [ 1772 (None, Ok(())), 1773 (Some(2), Err("hello there")), 1774 (Some(200), Err("general kenobi")), 1775 ]; 1776 let (ptr, len, list) = func.call(&mut store, (&input,))?; 1777 let memory = list.as_le_slice(&store); 1778 let ptr = usize::try_from(ptr).unwrap(); 1779 let len = usize::try_from(len).unwrap(); 1780 let mut array = &memory[ptr..][..len * 16]; 1781 1782 for (a, b) in input.iter() { 1783 match a { 1784 Some(val) => { 1785 assert_eq!(*array.take_n::<2>(), [1, *val]); 1786 } 1787 None => { 1788 assert_eq!(*array.take_n::<1>(), [0]); 1789 array.skip::<1>(); 1790 } 1791 } 1792 array.skip::<2>(); 1793 match b { 1794 Ok(()) => { 1795 assert_eq!(*array.take_n::<1>(), [0]); 1796 array.skip::<11>(); 1797 } 1798 Err(s) => { 1799 assert_eq!(*array.take_n::<1>(), [1]); 1800 array.skip::<3>(); 1801 assert_eq!(array.ptr_len(memory, 1), s.as_bytes()); 1802 } 1803 } 1804 } 1805 assert!(array.is_empty()); 1806 1807 Ok(()) 1808 } 1809 1810 trait SliceExt<'a> { 1811 fn take_n<const N: usize>(&mut self) -> &'a [u8; N]; 1812 1813 fn skip<const N: usize>(&mut self) { 1814 self.take_n::<N>(); 1815 } 1816 1817 fn ptr_len<'b>(&mut self, all_memory: &'b [u8], size: usize) -> &'b [u8] { 1818 let ptr = u32::from_le_bytes(*self.take_n::<4>()); 1819 let len = u32::from_le_bytes(*self.take_n::<4>()); 1820 let ptr = usize::try_from(ptr).unwrap(); 1821 let len = usize::try_from(len).unwrap(); 1822 &all_memory[ptr..][..len * size] 1823 } 1824 } 1825 1826 impl<'a> SliceExt<'a> for &'a [u8] { 1827 fn take_n<const N: usize>(&mut self) -> &'a [u8; N] { 1828 let (a, b) = self.split_at(N); 1829 *self = b; 1830 a.try_into().unwrap() 1831 } 1832 } 1833 1834 #[test] 1835 fn invalid_alignment() -> Result<()> { 1836 let component = format!( 1837 r#"(component 1838 (core module $m 1839 (memory (export "memory") 1) 1840 (func (export "realloc") (param i32 i32 i32 i32) (result i32) 1841 i32.const 1) 1842 1843 (func (export "take-i32") (param i32)) 1844 (func (export "ret-1") (result i32) i32.const 1) 1845 (func (export "ret-unaligned-list") (result i32) 1846 (i32.store offset=0 (i32.const 8) (i32.const 1)) 1847 (i32.store offset=4 (i32.const 8) (i32.const 1)) 1848 i32.const 8) 1849 ) 1850 (core instance $i (instantiate $m)) 1851 1852 (func (export "many-params") 1853 (param "s1" string) (param "s2" string) (param "s3" string) (param "s4" string) 1854 (param "s5" string) (param "s6" string) (param "s7" string) (param "s8" string) 1855 (param "s9" string) (param "s10" string) (param "s11" string) (param "s12" string) 1856 (canon lift 1857 (core func $i "take-i32") 1858 (memory $i "memory") 1859 (realloc (func $i "realloc")) 1860 ) 1861 ) 1862 (func (export "string-ret") (result string) 1863 (canon lift 1864 (core func $i "ret-1") 1865 (memory $i "memory") 1866 (realloc (func $i "realloc")) 1867 ) 1868 ) 1869 (func (export "list-u32-ret") (result (list u32)) 1870 (canon lift 1871 (core func $i "ret-unaligned-list") 1872 (memory $i "memory") 1873 (realloc (func $i "realloc")) 1874 ) 1875 ) 1876 )"# 1877 ); 1878 1879 let engine = super::engine(); 1880 let component = Component::new(&engine, component)?; 1881 let mut store = Store::new(&engine, ()); 1882 let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component); 1883 1884 let err = instance(&mut store)? 1885 .get_typed_func::<( 1886 &str, 1887 &str, 1888 &str, 1889 &str, 1890 &str, 1891 &str, 1892 &str, 1893 &str, 1894 &str, 1895 &str, 1896 &str, 1897 &str, 1898 ), ()>(&mut store, "many-params")? 1899 .call(&mut store, ("", "", "", "", "", "", "", "", "", "", "", "")) 1900 .unwrap_err(); 1901 assert!( 1902 err.to_string() 1903 .contains("realloc return: result not aligned"), 1904 "{}", 1905 err 1906 ); 1907 1908 let err = instance(&mut store)? 1909 .get_typed_func::<(), (WasmStr,)>(&mut store, "string-ret")? 1910 .call(&mut store, ()) 1911 .err() 1912 .unwrap(); 1913 assert!( 1914 err.to_string().contains("return pointer not aligned"), 1915 "{}", 1916 err 1917 ); 1918 1919 let err = instance(&mut store)? 1920 .get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32-ret")? 1921 .call(&mut store, ()) 1922 .err() 1923 .unwrap(); 1924 assert!( 1925 err.to_string().contains("list pointer is not aligned"), 1926 "{}", 1927 err 1928 ); 1929 1930 Ok(()) 1931 } 1932 1933 #[test] 1934 fn drop_component_still_works() -> Result<()> { 1935 let component = r#" 1936 (component 1937 (import "f" (func $f)) 1938 1939 (core func $f_lower 1940 (canon lower (func $f)) 1941 ) 1942 (core module $m 1943 (import "" "" (func $f)) 1944 1945 (func $f2 1946 call $f 1947 call $f 1948 ) 1949 1950 (export "f" (func $f2)) 1951 ) 1952 (core instance $i (instantiate $m 1953 (with "" (instance 1954 (export "" (func $f_lower)) 1955 )) 1956 )) 1957 (func (export "g") 1958 (canon lift 1959 (core func $i "f") 1960 ) 1961 ) 1962 ) 1963 "#; 1964 1965 let (mut store, instance) = { 1966 let engine = super::engine(); 1967 let component = Component::new(&engine, component)?; 1968 let mut store = Store::new(&engine, 0); 1969 let mut linker = Linker::new(&engine); 1970 linker.root().func_wrap( 1971 "f", 1972 |mut store: StoreContextMut<'_, u32>, _: ()| -> Result<()> { 1973 *store.data_mut() += 1; 1974 Ok(()) 1975 }, 1976 )?; 1977 let instance = linker.instantiate(&mut store, &component)?; 1978 (store, instance) 1979 }; 1980 1981 let f = instance.get_typed_func::<(), ()>(&mut store, "g")?; 1982 assert_eq!(*store.data(), 0); 1983 f.call(&mut store, ())?; 1984 assert_eq!(*store.data(), 2); 1985 1986 Ok(()) 1987 } 1988 1989 #[test] 1990 fn raw_slice_of_various_types() -> Result<()> { 1991 let component = r#" 1992 (component 1993 (core module $m 1994 (memory (export "memory") 1) 1995 1996 (func (export "list8") (result i32) 1997 (call $setup_list (i32.const 16)) 1998 ) 1999 (func (export "list16") (result i32) 2000 (call $setup_list (i32.const 8)) 2001 ) 2002 (func (export "list32") (result i32) 2003 (call $setup_list (i32.const 4)) 2004 ) 2005 (func (export "list64") (result i32) 2006 (call $setup_list (i32.const 2)) 2007 ) 2008 2009 (func $setup_list (param i32) (result i32) 2010 (i32.store offset=0 (i32.const 100) (i32.const 8)) 2011 (i32.store offset=4 (i32.const 100) (local.get 0)) 2012 i32.const 100 2013 ) 2014 2015 (data (i32.const 8) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f") 2016 ) 2017 (core instance $i (instantiate $m)) 2018 (func (export "list-u8") (result (list u8)) 2019 (canon lift (core func $i "list8") (memory $i "memory")) 2020 ) 2021 (func (export "list-i8") (result (list s8)) 2022 (canon lift (core func $i "list8") (memory $i "memory")) 2023 ) 2024 (func (export "list-u16") (result (list u16)) 2025 (canon lift (core func $i "list16") (memory $i "memory")) 2026 ) 2027 (func (export "list-i16") (result (list s16)) 2028 (canon lift (core func $i "list16") (memory $i "memory")) 2029 ) 2030 (func (export "list-u32") (result (list u32)) 2031 (canon lift (core func $i "list32") (memory $i "memory")) 2032 ) 2033 (func (export "list-i32") (result (list s32)) 2034 (canon lift (core func $i "list32") (memory $i "memory")) 2035 ) 2036 (func (export "list-u64") (result (list u64)) 2037 (canon lift (core func $i "list64") (memory $i "memory")) 2038 ) 2039 (func (export "list-i64") (result (list s64)) 2040 (canon lift (core func $i "list64") (memory $i "memory")) 2041 ) 2042 ) 2043 "#; 2044 2045 let (mut store, instance) = { 2046 let engine = super::engine(); 2047 let component = Component::new(&engine, component)?; 2048 let mut store = Store::new(&engine, ()); 2049 let instance = Linker::new(&engine).instantiate(&mut store, &component)?; 2050 (store, instance) 2051 }; 2052 2053 let list = instance 2054 .get_typed_func::<(), (WasmList<u8>,)>(&mut store, "list-u8")? 2055 .call_and_post_return(&mut store, ())? 2056 .0; 2057 assert_eq!( 2058 list.as_le_slice(&store), 2059 [ 2060 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 2061 0x0e, 0x0f, 2062 ] 2063 ); 2064 let list = instance 2065 .get_typed_func::<(), (WasmList<i8>,)>(&mut store, "list-i8")? 2066 .call_and_post_return(&mut store, ())? 2067 .0; 2068 assert_eq!( 2069 list.as_le_slice(&store), 2070 [ 2071 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 2072 0x0e, 0x0f, 2073 ] 2074 ); 2075 2076 let list = instance 2077 .get_typed_func::<(), (WasmList<u16>,)>(&mut store, "list-u16")? 2078 .call_and_post_return(&mut store, ())? 2079 .0; 2080 assert_eq!( 2081 list.as_le_slice(&store), 2082 [ 2083 u16::to_le(0x01_00), 2084 u16::to_le(0x03_02), 2085 u16::to_le(0x05_04), 2086 u16::to_le(0x07_06), 2087 u16::to_le(0x09_08), 2088 u16::to_le(0x0b_0a), 2089 u16::to_le(0x0d_0c), 2090 u16::to_le(0x0f_0e), 2091 ] 2092 ); 2093 let list = instance 2094 .get_typed_func::<(), (WasmList<i16>,)>(&mut store, "list-i16")? 2095 .call_and_post_return(&mut store, ())? 2096 .0; 2097 assert_eq!( 2098 list.as_le_slice(&store), 2099 [ 2100 i16::to_le(0x01_00), 2101 i16::to_le(0x03_02), 2102 i16::to_le(0x05_04), 2103 i16::to_le(0x07_06), 2104 i16::to_le(0x09_08), 2105 i16::to_le(0x0b_0a), 2106 i16::to_le(0x0d_0c), 2107 i16::to_le(0x0f_0e), 2108 ] 2109 ); 2110 let list = instance 2111 .get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32")? 2112 .call_and_post_return(&mut store, ())? 2113 .0; 2114 assert_eq!( 2115 list.as_le_slice(&store), 2116 [ 2117 u32::to_le(0x03_02_01_00), 2118 u32::to_le(0x07_06_05_04), 2119 u32::to_le(0x0b_0a_09_08), 2120 u32::to_le(0x0f_0e_0d_0c), 2121 ] 2122 ); 2123 let list = instance 2124 .get_typed_func::<(), (WasmList<i32>,)>(&mut store, "list-i32")? 2125 .call_and_post_return(&mut store, ())? 2126 .0; 2127 assert_eq!( 2128 list.as_le_slice(&store), 2129 [ 2130 i32::to_le(0x03_02_01_00), 2131 i32::to_le(0x07_06_05_04), 2132 i32::to_le(0x0b_0a_09_08), 2133 i32::to_le(0x0f_0e_0d_0c), 2134 ] 2135 ); 2136 let list = instance 2137 .get_typed_func::<(), (WasmList<u64>,)>(&mut store, "list-u64")? 2138 .call_and_post_return(&mut store, ())? 2139 .0; 2140 assert_eq!( 2141 list.as_le_slice(&store), 2142 [ 2143 u64::to_le(0x07_06_05_04_03_02_01_00), 2144 u64::to_le(0x0f_0e_0d_0c_0b_0a_09_08), 2145 ] 2146 ); 2147 let list = instance 2148 .get_typed_func::<(), (WasmList<i64>,)>(&mut store, "list-i64")? 2149 .call_and_post_return(&mut store, ())? 2150 .0; 2151 assert_eq!( 2152 list.as_le_slice(&store), 2153 [ 2154 i64::to_le(0x07_06_05_04_03_02_01_00), 2155 i64::to_le(0x0f_0e_0d_0c_0b_0a_09_08), 2156 ] 2157 ); 2158 2159 Ok(()) 2160 } 2161 2162 #[test] 2163 fn lower_then_lift() -> Result<()> { 2164 // First test simple integers when the import/export ABI happen to line up 2165 let component = r#" 2166 (component $c 2167 (import "f" (func $f (result u32))) 2168 2169 (core func $f_lower 2170 (canon lower (func $f)) 2171 ) 2172 (func $f2 (result s32) 2173 (canon lift (core func $f_lower)) 2174 ) 2175 (export "f2" (func $f2)) 2176 ) 2177 "#; 2178 2179 let engine = super::engine(); 2180 let component = Component::new(&engine, component)?; 2181 let mut store = Store::new(&engine, ()); 2182 let mut linker = Linker::new(&engine); 2183 linker.root().func_wrap("f", |_, _: ()| Ok((2u32,)))?; 2184 let instance = linker.instantiate(&mut store, &component)?; 2185 2186 let f = instance.get_typed_func::<(), (i32,)>(&mut store, "f2")?; 2187 assert_eq!(f.call(&mut store, ())?, (2,)); 2188 2189 // First test strings when the import/export ABI happen to line up 2190 let component = format!( 2191 r#" 2192 (component $c 2193 (import "s" (func $f (param "a" string))) 2194 2195 (core module $libc 2196 (memory (export "memory") 1) 2197 {REALLOC_AND_FREE} 2198 ) 2199 (core instance $libc (instantiate $libc)) 2200 2201 (core func $f_lower 2202 (canon lower (func $f) (memory $libc "memory")) 2203 ) 2204 (func $f2 (param "a" string) 2205 (canon lift (core func $f_lower) 2206 (memory $libc "memory") 2207 (realloc (func $libc "realloc")) 2208 ) 2209 ) 2210 (export "f" (func $f2)) 2211 ) 2212 "# 2213 ); 2214 2215 let component = Component::new(&engine, component)?; 2216 let mut store = Store::new(&engine, ()); 2217 linker 2218 .root() 2219 .func_wrap("s", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| { 2220 assert_eq!(x.to_str(&store)?, "hello"); 2221 Ok(()) 2222 })?; 2223 let instance = linker.instantiate(&mut store, &component)?; 2224 2225 let f = instance.get_typed_func::<(&str,), ()>(&mut store, "f")?; 2226 f.call(&mut store, ("hello",))?; 2227 2228 // Next test "type punning" where return values are reinterpreted just 2229 // because the return ABI happens to line up. 2230 let component = format!( 2231 r#" 2232 (component $c 2233 (import "s2" (func $f (param "a" string) (result u32))) 2234 2235 (core module $libc 2236 (memory (export "memory") 1) 2237 {REALLOC_AND_FREE} 2238 ) 2239 (core instance $libc (instantiate $libc)) 2240 2241 (core func $f_lower 2242 (canon lower (func $f) (memory $libc "memory")) 2243 ) 2244 (func $f2 (param "a" string) (result string) 2245 (canon lift (core func $f_lower) 2246 (memory $libc "memory") 2247 (realloc (func $libc "realloc")) 2248 ) 2249 ) 2250 (export "f" (func $f2)) 2251 ) 2252 "# 2253 ); 2254 2255 let component = Component::new(&engine, component)?; 2256 let mut store = Store::new(&engine, ()); 2257 linker 2258 .root() 2259 .func_wrap("s2", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| { 2260 assert_eq!(x.to_str(&store)?, "hello"); 2261 Ok((u32::MAX,)) 2262 })?; 2263 let instance = linker.instantiate(&mut store, &component)?; 2264 2265 let f = instance.get_typed_func::<(&str,), (WasmStr,)>(&mut store, "f")?; 2266 let err = f.call(&mut store, ("hello",)).err().unwrap(); 2267 assert!( 2268 err.to_string().contains("return pointer not aligned"), 2269 "{}", 2270 err 2271 ); 2272 2273 Ok(()) 2274 } 2275 2276 #[test] 2277 fn errors_that_poison_instance() -> Result<()> { 2278 let component = format!( 2279 r#" 2280 (component $c 2281 (core module $m1 2282 (func (export "f1") unreachable) 2283 (func (export "f2")) 2284 ) 2285 (core instance $m1 (instantiate $m1)) 2286 (func (export "f1") (canon lift (core func $m1 "f1"))) 2287 (func (export "f2") (canon lift (core func $m1 "f2"))) 2288 2289 (core module $m2 2290 (func (export "f") (param i32 i32)) 2291 (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) 2292 (memory (export "m") 1) 2293 ) 2294 (core instance $m2 (instantiate $m2)) 2295 (func (export "f3") (param "a" string) 2296 (canon lift (core func $m2 "f") (realloc (func $m2 "r")) (memory $m2 "m")) 2297 ) 2298 2299 (core module $m3 2300 (func (export "f") (result i32) i32.const 1) 2301 (memory (export "m") 1) 2302 ) 2303 (core instance $m3 (instantiate $m3)) 2304 (func (export "f4") (result string) 2305 (canon lift (core func $m3 "f") (memory $m3 "m")) 2306 ) 2307 ) 2308 "# 2309 ); 2310 2311 let engine = super::engine(); 2312 let component = Component::new(&engine, component)?; 2313 let mut store = Store::new(&engine, ()); 2314 let linker = Linker::new(&engine); 2315 let instance = linker.instantiate(&mut store, &component)?; 2316 let f1 = instance.get_typed_func::<(), ()>(&mut store, "f1")?; 2317 let f2 = instance.get_typed_func::<(), ()>(&mut store, "f2")?; 2318 assert_unreachable(f1.call(&mut store, ())); 2319 assert_poisoned(f1.call(&mut store, ())); 2320 assert_poisoned(f2.call(&mut store, ())); 2321 2322 let instance = linker.instantiate(&mut store, &component)?; 2323 let f3 = instance.get_typed_func::<(&str,), ()>(&mut store, "f3")?; 2324 assert_unreachable(f3.call(&mut store, ("x",))); 2325 assert_poisoned(f3.call(&mut store, ("x",))); 2326 2327 let instance = linker.instantiate(&mut store, &component)?; 2328 let f4 = instance.get_typed_func::<(), (WasmStr,)>(&mut store, "f4")?; 2329 assert!(f4.call(&mut store, ()).is_err()); 2330 assert_poisoned(f4.call(&mut store, ())); 2331 2332 return Ok(()); 2333 2334 #[track_caller] 2335 fn assert_unreachable<T>(err: Result<T>) { 2336 let err = match err { 2337 Ok(_) => panic!("expected an error"), 2338 Err(e) => e, 2339 }; 2340 assert_eq!( 2341 err.downcast::<Trap>().unwrap(), 2342 Trap::UnreachableCodeReached 2343 ); 2344 } 2345 2346 #[track_caller] 2347 fn assert_poisoned<T>(err: Result<T>) { 2348 let err = match err { 2349 Ok(_) => panic!("expected an error"), 2350 Err(e) => e, 2351 }; 2352 assert_eq!( 2353 err.downcast_ref::<Trap>(), 2354 Some(&Trap::CannotEnterComponent), 2355 "{err}", 2356 ); 2357 } 2358 } 2359 2360 #[test] 2361 fn run_export_with_internal_adapter() -> Result<()> { 2362 let component = r#" 2363 (component 2364 (type $t (func (param "a" u32) (result u32))) 2365 (component $a 2366 (core module $m 2367 (func (export "add-five") (param i32) (result i32) 2368 local.get 0 2369 i32.const 5 2370 i32.add) 2371 ) 2372 (core instance $m (instantiate $m)) 2373 (func (export "add-five") (type $t) (canon lift (core func $m "add-five"))) 2374 ) 2375 (component $b 2376 (import "interface-v1" (instance $i 2377 (export "add-five" (func (type $t))))) 2378 (core module $m 2379 (func $add-five (import "interface-0.1.0" "add-five") (param i32) (result i32)) 2380 (func) ;; causes index out of bounds 2381 (func (export "run") (result i32) i32.const 0 call $add-five) 2382 ) 2383 (core func $add-five (canon lower (func $i "add-five"))) 2384 (core instance $i (instantiate 0 2385 (with "interface-0.1.0" (instance 2386 (export "add-five" (func $add-five)) 2387 )) 2388 )) 2389 (func (result u32) (canon lift (core func $i "run"))) 2390 (export "run" (func 1)) 2391 ) 2392 (instance $a (instantiate $a)) 2393 (instance $b (instantiate $b (with "interface-v1" (instance $a)))) 2394 (export "run" (func $b "run")) 2395 ) 2396 "#; 2397 let engine = super::engine(); 2398 let component = Component::new(&engine, component)?; 2399 let mut store = Store::new(&engine, ()); 2400 let linker = Linker::new(&engine); 2401 let instance = linker.instantiate(&mut store, &component)?; 2402 let run = instance.get_typed_func::<(), (u32,)>(&mut store, "run")?; 2403 assert_eq!(run.call(&mut store, ())?, (5,)); 2404 Ok(()) 2405 } 2406