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