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