1 use anyhow::bail; 2 use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; 3 use wasmtime::*; 4 5 #[test] 6 #[should_panic = "cannot use `func_new_async` without enabling async support"] 7 fn async_required() { 8 let engine = Engine::default(); 9 let mut linker = Linker::<()>::new(&engine); 10 drop(linker.func_new_async( 11 "", 12 "", 13 FuncType::new(&engine, None, None), 14 move |_caller, _params, _results| Box::new(async { Ok(()) }), 15 )); 16 } 17 18 #[test] 19 fn wrap_func() -> Result<()> { 20 let engine = Engine::default(); 21 let mut linker = Linker::<()>::new(&engine); 22 linker.allow_shadowing(true); 23 24 linker.func_wrap("", "", || {})?; 25 linker.func_wrap("m", "f", |_: i32| {})?; 26 linker.func_wrap("m", "f2", |_: i32, _: i64| {})?; 27 linker.func_wrap("m2", "f", |_: f32, _: f64| {})?; 28 linker.func_wrap("m2", "f2", || -> i32 { 0 })?; 29 linker.func_wrap("", "", || -> i64 { 0 })?; 30 linker.func_wrap("m", "f", || -> f32 { 0.0 })?; 31 linker.func_wrap("m2", "f", || -> f64 { 0.0 })?; 32 linker.func_wrap("m3", "", || -> Option<Rooted<ExternRef>> { None })?; 33 linker.func_wrap("m3", "f", || -> Option<Func> { None })?; 34 35 linker.func_wrap("", "f1", || -> Result<()> { 36 loop {} 37 })?; 38 linker.func_wrap("", "f2", || -> Result<i32> { 39 loop {} 40 })?; 41 linker.func_wrap("", "f3", || -> Result<i64> { 42 loop {} 43 })?; 44 linker.func_wrap("", "f4", || -> Result<f32> { 45 loop {} 46 })?; 47 linker.func_wrap("", "f5", || -> Result<f64> { 48 loop {} 49 })?; 50 linker.func_wrap("", "f6", || -> Result<Option<Rooted<ExternRef>>> { 51 loop {} 52 })?; 53 linker.func_wrap("", "f7", || -> Result<Option<Func>> { 54 loop {} 55 })?; 56 Ok(()) 57 } 58 59 #[test] 60 fn drop_func() -> Result<()> { 61 static HITS: AtomicUsize = AtomicUsize::new(0); 62 struct A; 63 64 impl Drop for A { 65 fn drop(&mut self) { 66 HITS.fetch_add(1, SeqCst); 67 } 68 } 69 70 let engine = Engine::default(); 71 let mut linker = Linker::<()>::new(&engine); 72 linker.allow_shadowing(true); 73 74 let a = A; 75 linker.func_wrap("", "", move || { 76 let _ = &a; 77 })?; 78 79 assert_eq!(HITS.load(SeqCst), 0); 80 81 // Define the function again to ensure redefined functions are dropped 82 83 let a = A; 84 linker.func_wrap("", "", move || { 85 let _ = &a; 86 })?; 87 88 assert_eq!(HITS.load(SeqCst), 1); 89 90 drop(linker); 91 92 assert_eq!(HITS.load(SeqCst), 2); 93 94 Ok(()) 95 } 96 97 #[test] 98 #[cfg_attr(miri, ignore)] 99 fn drop_delayed() -> Result<()> { 100 static HITS: AtomicUsize = AtomicUsize::new(0); 101 102 struct A; 103 104 impl Drop for A { 105 fn drop(&mut self) { 106 HITS.fetch_add(1, SeqCst); 107 } 108 } 109 110 let engine = Engine::default(); 111 let mut linker = Linker::<()>::new(&engine); 112 113 let a = A; 114 linker.func_wrap("", "", move || { 115 let _ = &a; 116 })?; 117 118 assert_eq!(HITS.load(SeqCst), 0); 119 120 let module = Module::new(&engine, &wat::parse_str(r#"(import "" "" (func))"#)?)?; 121 122 let mut store = Store::new(&engine, ()); 123 let func = linker.get(&mut store, "", "").unwrap(); 124 Instance::new(&mut store, &module, &[func])?; 125 126 drop(store); 127 128 assert_eq!(HITS.load(SeqCst), 0); 129 130 let mut store = Store::new(&engine, ()); 131 let func = linker.get(&mut store, "", "").unwrap(); 132 Instance::new(&mut store, &module, &[func])?; 133 134 drop(store); 135 136 assert_eq!(HITS.load(SeqCst), 0); 137 138 drop(linker); 139 140 assert_eq!(HITS.load(SeqCst), 1); 141 142 Ok(()) 143 } 144 145 #[test] 146 fn signatures_match() -> Result<()> { 147 let engine = Engine::default(); 148 let mut linker = Linker::<()>::new(&engine); 149 150 linker.func_wrap("", "f1", || {})?; 151 linker.func_wrap("", "f2", || -> i32 { 152 loop {} 153 })?; 154 linker.func_wrap("", "f3", || -> i64 { 155 loop {} 156 })?; 157 linker.func_wrap("", "f4", || -> f32 { 158 loop {} 159 })?; 160 linker.func_wrap("", "f5", || -> f64 { 161 loop {} 162 })?; 163 linker.func_wrap( 164 "", 165 "f6", 166 |_: f32, 167 _: f64, 168 _: i32, 169 _: i64, 170 _: i32, 171 _: Option<Rooted<ExternRef>>, 172 _: Option<Func>| 173 -> f64 { loop {} }, 174 )?; 175 176 let mut store = Store::new(&engine, ()); 177 178 let f = linker 179 .get(&mut store, "", "f1") 180 .unwrap() 181 .into_func() 182 .unwrap(); 183 assert_eq!(f.ty(&store).params().len(), 0); 184 assert_eq!(f.ty(&store).results().len(), 0); 185 186 let f = linker 187 .get(&mut store, "", "f2") 188 .unwrap() 189 .into_func() 190 .unwrap(); 191 assert_eq!(f.ty(&store).params().len(), 0); 192 assert_eq!(f.ty(&store).results().len(), 1); 193 assert!(f.ty(&store).results().nth(0).unwrap().is_i32()); 194 195 let f = linker 196 .get(&mut store, "", "f3") 197 .unwrap() 198 .into_func() 199 .unwrap(); 200 assert_eq!(f.ty(&store).params().len(), 0); 201 assert_eq!(f.ty(&store).results().len(), 1); 202 assert!(f.ty(&store).results().nth(0).unwrap().is_i64()); 203 204 let f = linker 205 .get(&mut store, "", "f4") 206 .unwrap() 207 .into_func() 208 .unwrap(); 209 assert_eq!(f.ty(&store).params().len(), 0); 210 assert_eq!(f.ty(&store).results().len(), 1); 211 assert!(f.ty(&store).results().nth(0).unwrap().is_f32()); 212 213 let f = linker 214 .get(&mut store, "", "f5") 215 .unwrap() 216 .into_func() 217 .unwrap(); 218 assert_eq!(f.ty(&store).params().len(), 0); 219 assert_eq!(f.ty(&store).results().len(), 1); 220 assert!(f.ty(&store).results().nth(0).unwrap().is_f64()); 221 222 let f = linker 223 .get(&mut store, "", "f6") 224 .unwrap() 225 .into_func() 226 .unwrap(); 227 228 assert_eq!(f.ty(&store).params().len(), 7); 229 assert!(f.ty(&store).params().nth(0).unwrap().is_f32()); 230 assert!(f.ty(&store).params().nth(1).unwrap().is_f64()); 231 assert!(f.ty(&store).params().nth(2).unwrap().is_i32()); 232 assert!(f.ty(&store).params().nth(3).unwrap().is_i64()); 233 assert!(f.ty(&store).params().nth(4).unwrap().is_i32()); 234 assert!(f.ty(&store).params().nth(5).unwrap().is_externref()); 235 assert!(f.ty(&store).params().nth(6).unwrap().is_funcref()); 236 237 assert_eq!(f.ty(&store).results().len(), 1); 238 assert!(f.ty(&store).results().nth(0).unwrap().is_f64()); 239 240 Ok(()) 241 } 242 243 #[test] 244 #[cfg_attr(miri, ignore)] 245 fn import_works() -> Result<()> { 246 static HITS: AtomicUsize = AtomicUsize::new(0); 247 248 let wasm = wat::parse_str( 249 r#" 250 (import "" "f1" (func)) 251 (import "" "f2" (func (param i32) (result i32))) 252 (import "" "f3" (func (param i32) (param i64))) 253 (import "" "f4" (func (param i32 i64 i32 f32 f64 externref funcref))) 254 255 (func (export "run") (param externref funcref) 256 call 0 257 i32.const 0 258 call 1 259 i32.const 1 260 i32.add 261 i64.const 3 262 call 2 263 264 i32.const 100 265 i64.const 200 266 i32.const 300 267 f32.const 400 268 f64.const 500 269 local.get 0 270 local.get 1 271 call 3 272 ) 273 "#, 274 )?; 275 276 let engine = Engine::default(); 277 let mut linker = Linker::<()>::new(&engine); 278 279 linker.func_wrap("", "f1", || { 280 assert_eq!(HITS.fetch_add(1, SeqCst), 0); 281 })?; 282 283 linker.func_wrap("", "f2", |x: i32| -> i32 { 284 assert_eq!(x, 0); 285 assert_eq!(HITS.fetch_add(1, SeqCst), 1); 286 1 287 })?; 288 289 linker.func_wrap("", "f3", |x: i32, y: i64| { 290 assert_eq!(x, 2); 291 assert_eq!(y, 3); 292 assert_eq!(HITS.fetch_add(1, SeqCst), 2); 293 })?; 294 295 linker.func_wrap( 296 "", 297 "f4", 298 |mut caller: Caller<'_, _>, 299 a: i32, 300 b: i64, 301 c: i32, 302 d: f32, 303 e: f64, 304 f: Option<Rooted<ExternRef>>, 305 g: Option<Func>| { 306 assert_eq!(a, 100); 307 assert_eq!(b, 200); 308 assert_eq!(c, 300); 309 assert_eq!(d, 400.0); 310 assert_eq!(e, 500.0); 311 assert_eq!( 312 f.as_ref() 313 .unwrap() 314 .data(&caller) 315 .unwrap() 316 .unwrap() 317 .downcast_ref::<String>() 318 .unwrap(), 319 "hello" 320 ); 321 let mut results = [Val::I32(0)]; 322 g.as_ref() 323 .unwrap() 324 .call(&mut caller, &[], &mut results) 325 .unwrap(); 326 assert_eq!(results[0].unwrap_i32(), 42); 327 assert_eq!(HITS.fetch_add(1, SeqCst), 3); 328 }, 329 )?; 330 331 let module = Module::new(&engine, &wasm)?; 332 333 let mut store = Store::new(&engine, ()); 334 let instance = linker.instantiate(&mut store, &module)?; 335 let run = instance.get_func(&mut store, "run").unwrap(); 336 let funcref = Val::FuncRef(Some(Func::wrap(&mut store, || -> i32 { 42 }))); 337 let externref = Val::ExternRef(Some(ExternRef::new(&mut store, "hello".to_string())?)); 338 run.call(&mut store, &[externref, funcref], &mut [])?; 339 340 assert_eq!(HITS.load(SeqCst), 4); 341 342 Ok(()) 343 } 344 345 #[test] 346 #[cfg_attr(miri, ignore)] 347 fn call_import_many_args() -> Result<()> { 348 let wasm = wat::parse_str( 349 r#" 350 (import "" "host" (func (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32))) 351 (func (export "run") 352 i32.const 1 353 i32.const 2 354 i32.const 3 355 i32.const 4 356 i32.const 5 357 i32.const 6 358 i32.const 7 359 i32.const 8 360 i32.const 9 361 i32.const 10 362 call 0 363 ) 364 "#, 365 )?; 366 367 let engine = Engine::default(); 368 let mut linker = Linker::<()>::new(&engine); 369 370 linker.func_wrap( 371 "", 372 "host", 373 |x1: i32, 374 x2: i32, 375 x3: i32, 376 x4: i32, 377 x5: i32, 378 x6: i32, 379 x7: i32, 380 x8: i32, 381 x9: i32, 382 x10: i32| { 383 assert_eq!(x1, 1); 384 assert_eq!(x2, 2); 385 assert_eq!(x3, 3); 386 assert_eq!(x4, 4); 387 assert_eq!(x5, 5); 388 assert_eq!(x6, 6); 389 assert_eq!(x7, 7); 390 assert_eq!(x8, 8); 391 assert_eq!(x9, 9); 392 assert_eq!(x10, 10); 393 }, 394 )?; 395 396 let module = Module::new(&engine, &wasm)?; 397 let mut store = Store::new(&engine, ()); 398 let instance = linker.instantiate(&mut store, &module)?; 399 let run = instance.get_func(&mut store, "run").unwrap(); 400 run.call(&mut store, &[], &mut [])?; 401 402 Ok(()) 403 } 404 405 #[test] 406 #[cfg_attr(miri, ignore)] 407 fn call_wasm_many_args() -> Result<()> { 408 let wasm = wat::parse_str( 409 r#" 410 (func (export "run") (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) 411 i32.const 1 412 local.get 0 413 i32.ne 414 if 415 unreachable 416 end 417 418 i32.const 10 419 local.get 9 420 i32.ne 421 if 422 unreachable 423 end 424 ) 425 426 (func (export "test") 427 i32.const 1 428 i32.const 2 429 i32.const 3 430 i32.const 4 431 i32.const 5 432 i32.const 6 433 i32.const 7 434 i32.const 8 435 i32.const 9 436 i32.const 10 437 call 0 438 ) 439 "#, 440 )?; 441 442 let engine = Engine::default(); 443 let module = Module::new(&engine, &wasm)?; 444 445 let mut store = Store::new(&engine, ()); 446 let instance = Instance::new(&mut store, &module, &[])?; 447 448 let run = instance.get_func(&mut store, "run").unwrap(); 449 run.call( 450 &mut store, 451 &[ 452 1.into(), 453 2.into(), 454 3.into(), 455 4.into(), 456 5.into(), 457 6.into(), 458 7.into(), 459 8.into(), 460 9.into(), 461 10.into(), 462 ], 463 &mut [], 464 )?; 465 466 let typed_run = instance 467 .get_typed_func::<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32), ()>( 468 &mut store, "run", 469 )?; 470 typed_run.call(&mut store, (1, 2, 3, 4, 5, 6, 7, 8, 9, 10))?; 471 472 let test = instance.get_func(&mut store, "test").unwrap(); 473 test.call(&mut store, &[], &mut [])?; 474 475 Ok(()) 476 } 477 478 #[test] 479 #[cfg_attr(miri, ignore)] 480 fn trap_smoke() -> Result<()> { 481 let engine = Engine::default(); 482 let mut linker = Linker::<()>::new(&engine); 483 linker.func_wrap("", "", || -> Result<()> { bail!("test") })?; 484 485 let mut store = Store::new(&engine, ()); 486 487 let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap(); 488 489 let err = f.call(&mut store, &[], &mut []).unwrap_err(); 490 491 assert!(err.to_string().contains("test")); 492 493 Ok(()) 494 } 495 496 #[test] 497 #[cfg_attr(miri, ignore)] 498 fn trap_import() -> Result<()> { 499 let wasm = wat::parse_str( 500 r#" 501 (import "" "" (func)) 502 (start 0) 503 "#, 504 )?; 505 506 let engine = Engine::default(); 507 let mut linker = Linker::new(&engine); 508 linker.func_wrap("", "", || -> Result<()> { bail!("foo") })?; 509 510 let module = Module::new(&engine, &wasm)?; 511 let mut store = Store::new(&engine, ()); 512 513 let trap = linker.instantiate(&mut store, &module).unwrap_err(); 514 515 assert!(trap.to_string().contains("foo")); 516 517 Ok(()) 518 } 519 520 #[test] 521 #[cfg_attr(miri, ignore)] 522 fn new_from_signature() -> Result<()> { 523 let engine = Engine::default(); 524 let mut linker = Linker::new(&engine); 525 526 let ty = FuncType::new(&engine, None, None); 527 linker.func_new("", "f1", ty, |_, _, _| panic!())?; 528 529 let ty = FuncType::new(&engine, Some(ValType::I32), Some(ValType::F64)); 530 linker.func_new("", "f2", ty, |_, _, _| panic!())?; 531 532 let mut store = Store::new(&engine, ()); 533 534 let f = linker 535 .get(&mut store, "", "f1") 536 .unwrap() 537 .into_func() 538 .unwrap(); 539 assert!(f.typed::<(), ()>(&store).is_ok()); 540 assert!(f.typed::<(), i32>(&store).is_err()); 541 assert!(f.typed::<i32, ()>(&store).is_err()); 542 543 let f = linker 544 .get(&mut store, "", "f2") 545 .unwrap() 546 .into_func() 547 .unwrap(); 548 assert!(f.typed::<(), ()>(&store).is_err()); 549 assert!(f.typed::<(), i32>(&store).is_err()); 550 assert!(f.typed::<i32, ()>(&store).is_err()); 551 assert!(f.typed::<i32, f64>(&store).is_ok()); 552 553 Ok(()) 554 } 555 556 #[test] 557 fn call_wrapped_func() -> Result<()> { 558 let engine = Engine::default(); 559 let mut linker = Linker::new(&engine); 560 let mut results = [Val::I32(0)]; 561 562 linker.func_wrap("", "f1", |a: i32, b: i64, c: f32, d: f64| { 563 assert_eq!(a, 1); 564 assert_eq!(b, 2); 565 assert_eq!(c, 3.0); 566 assert_eq!(d, 4.0); 567 })?; 568 569 linker.func_wrap("", "f2", || 1i32)?; 570 571 linker.func_wrap("", "f3", || 2i64)?; 572 573 linker.func_wrap("", "f4", || 3.0f32)?; 574 575 linker.func_wrap("", "f5", || 4.0f64)?; 576 577 let mut store = Store::new(&engine, ()); 578 579 let f = linker 580 .get(&mut store, "", "f1") 581 .unwrap() 582 .into_func() 583 .unwrap(); 584 f.call( 585 &mut store, 586 &[Val::I32(1), Val::I64(2), 3.0f32.into(), 4.0f64.into()], 587 &mut [], 588 )?; 589 f.typed::<(i32, i64, f32, f64), ()>(&store)? 590 .call(&mut store, (1, 2, 3.0, 4.0))?; 591 592 let f = linker 593 .get(&mut store, "", "f2") 594 .unwrap() 595 .into_func() 596 .unwrap(); 597 f.call(&mut store, &[], &mut results)?; 598 assert_eq!(results[0].unwrap_i32(), 1); 599 assert_eq!(f.typed::<(), i32>(&store)?.call(&mut store, ())?, 1); 600 601 let f = linker 602 .get(&mut store, "", "f3") 603 .unwrap() 604 .into_func() 605 .unwrap(); 606 f.call(&mut store, &[], &mut results)?; 607 assert_eq!(results[0].unwrap_i64(), 2); 608 assert_eq!(f.typed::<(), i64>(&store)?.call(&mut store, ())?, 2); 609 610 let f = linker 611 .get(&mut store, "", "f4") 612 .unwrap() 613 .into_func() 614 .unwrap(); 615 f.call(&mut store, &[], &mut results)?; 616 assert_eq!(results[0].unwrap_f32(), 3.0); 617 assert_eq!(f.typed::<(), f32>(&store)?.call(&mut store, ())?, 3.0); 618 619 let f = linker 620 .get(&mut store, "", "f5") 621 .unwrap() 622 .into_func() 623 .unwrap(); 624 f.call(&mut store, &[], &mut results)?; 625 assert_eq!(results[0].unwrap_f64(), 4.0); 626 assert_eq!(f.typed::<(), f64>(&store)?.call(&mut store, ())?, 4.0); 627 628 Ok(()) 629 } 630 631 #[test] 632 #[cfg_attr(miri, ignore)] 633 fn func_return_nothing() -> Result<()> { 634 let engine = Engine::default(); 635 let mut linker = Linker::new(&engine); 636 let ty = FuncType::new(&engine, None, Some(ValType::I32)); 637 linker.func_new("", "", ty, |_, _, _| Ok(()))?; 638 639 let mut store = Store::new(&engine, ()); 640 let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap(); 641 let err = f.call(&mut store, &[], &mut [Val::I32(0)]).unwrap_err(); 642 assert!( 643 err.to_string() 644 .contains("function attempted to return an incompatible value") 645 ); 646 Ok(()) 647 } 648 649 #[test] 650 #[cfg_attr(miri, ignore)] 651 fn call_via_funcref() -> Result<()> { 652 static HITS: AtomicUsize = AtomicUsize::new(0); 653 654 struct A; 655 656 impl Drop for A { 657 fn drop(&mut self) { 658 HITS.fetch_add(1, SeqCst); 659 } 660 } 661 662 let wasm = wat::parse_str( 663 r#" 664 (table $t 1 funcref) 665 (type $add (func (param i32 i32) (result i32))) 666 (func (export "call") (param funcref) (result i32 funcref) 667 (table.set $t (i32.const 0) (local.get 0)) 668 (call_indirect (type $add) (i32.const 3) (i32.const 4) (i32.const 0)) 669 (local.get 0) 670 ) 671 "#, 672 )?; 673 674 let engine = Engine::default(); 675 let mut linker = Linker::new(&engine); 676 let a = A; 677 linker.func_wrap("", "", move |x: i32, y: i32| { 678 let _ = &a; 679 x + y 680 })?; 681 682 let module = Module::new(&engine, &wasm)?; 683 let mut store = Store::new(&engine, ()); 684 let instance = Instance::new(&mut store, &module, &[])?; 685 686 let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap(); 687 let mut results = [Val::I32(0), Val::I32(0)]; 688 instance 689 .get_func(&mut store, "call") 690 .unwrap() 691 .call(&mut store, &[f.into()], &mut results)?; 692 assert_eq!(results[0].unwrap_i32(), 7); 693 694 { 695 let f = results[1].unwrap_funcref().unwrap(); 696 let mut results = [Val::I32(0)]; 697 f.call(&mut store, &[1.into(), 2.into()], &mut results)?; 698 assert_eq!(results[0].unwrap_i32(), 3); 699 } 700 701 assert_eq!(HITS.load(SeqCst), 0); 702 703 drop(store); 704 705 assert_eq!(HITS.load(SeqCst), 0); 706 707 drop(linker); 708 709 assert_eq!(HITS.load(SeqCst), 1); 710 711 Ok(()) 712 } 713 714 #[test] 715 fn store_with_context() -> Result<()> { 716 struct Ctx { 717 called: bool, 718 } 719 720 let engine = Engine::default(); 721 let mut linker = Linker::new(&engine); 722 723 linker.func_wrap("", "", |mut caller: Caller<'_, Ctx>| { 724 caller.data_mut().called = true; 725 })?; 726 727 let mut store = Store::new(&engine, Ctx { called: false }); 728 729 let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap(); 730 f.call(&mut store, &[], &mut [])?; 731 732 assert!(store.data().called); 733 734 Ok(()) 735 } 736 737 #[test] 738 #[cfg_attr(miri, ignore)] 739 fn wasi_imports() -> Result<()> { 740 let engine = Engine::default(); 741 let mut linker = Linker::new(&engine); 742 wasmtime_wasi::p1::add_to_linker_sync(&mut linker, |t| t)?; 743 744 let wasm = wat::parse_str( 745 r#" 746 (import "wasi_snapshot_preview1" "proc_exit" (func $__wasi_proc_exit (param i32))) 747 (memory (export "memory") 0) 748 (func (export "_start") 749 (call $__wasi_proc_exit (i32.const 123)) 750 ) 751 "#, 752 )?; 753 754 let module = Module::new(&engine, wasm)?; 755 let mut store = Store::new(&engine, wasmtime_wasi::WasiCtxBuilder::new().build_p1()); 756 let instance = linker.instantiate(&mut store, &module)?; 757 758 let start = instance.get_typed_func::<(), ()>(&mut store, "_start")?; 759 let exit = start 760 .call(&mut store, ()) 761 .unwrap_err() 762 .downcast::<wasmtime_wasi::I32Exit>()?; 763 assert_eq!(exit.0, 123); 764 765 Ok(()) 766 } 767