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