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