xref: /wasmtime-44.0.1/tests/all/debug.rs (revision bda02c19)
1 //! Tests for instrumentation-based debugging.
2 
3 use std::sync::atomic::{AtomicUsize, Ordering};
4 use std::sync::{Arc, Mutex};
5 use wasmtime::{
6     AsContextMut, Caller, Config, DebugEvent, DebugHandler, Engine, Extern, FrameHandle, Func,
7     Global, GlobalType, Instance, Module, Mutability, Store, StoreContextMut, Val, ValType,
8 };
9 
10 use crate::async_functions::PollOnce;
11 
12 #[test]
13 fn debugging_does_not_work_with_signal_based_traps() {
14     let mut config = Config::default();
15     config.guest_debug(true).signals_based_traps(true);
16     let err = Engine::new(&config).expect_err("invalid config should produce an error");
17     assert!(format!("{err:?}").contains("cannot use signals-based traps"));
18 }
19 
20 #[test]
21 fn debugging_apis_are_denied_without_debugging() -> wasmtime::Result<()> {
22     let mut config = Config::default();
23     config.guest_debug(false);
24     let engine = Engine::new(&config)?;
25     let module = Module::new(&engine, "(module (global $g (mut i32) (i32.const 0)))")?;
26     let mut store = Store::new(&engine, ());
27     let instance = Instance::new(&mut store, &module, &[])?;
28 
29     assert!(store.debug_exit_frames().next().is_none());
30     assert!(instance.debug_global(&mut store, 0).is_none());
31 
32     Ok(())
33 }
34 
35 fn get_module_and_store<C: Fn(&mut Config)>(
36     c: C,
37     wat: &str,
38 ) -> wasmtime::Result<(Module, Store<()>)> {
39     let mut config = Config::default();
40     config.guest_debug(true);
41     config.wasm_exceptions(true);
42     c(&mut config);
43     let engine = Engine::new(&config)?;
44     let module = Module::new(&engine, wat)?;
45     Ok((module, Store::new(&engine, ())))
46 }
47 
48 fn test_stack_values<
49     C: Fn(&mut Config),
50     F: Fn(Caller<'_, ()>) -> wasmtime::Result<()> + Send + Sync + 'static,
51 >(
52     wat: &str,
53     c: C,
54     f: F,
55 ) -> wasmtime::Result<()> {
56     let (module, mut store) = get_module_and_store(c, wat)?;
57     let func = Func::wrap(&mut store, move |caller: Caller<'_, ()>| {
58         f(caller)?;
59         Ok(())
60     });
61     let instance = Instance::new(&mut store, &module, &[Extern::Func(func)])?;
62     let mut results = [];
63     instance
64         .get_func(&mut store, "main")
65         .unwrap()
66         .call(&mut store, &[], &mut results)?;
67 
68     Ok(())
69 }
70 
71 #[test]
72 #[cfg_attr(miri, ignore)]
73 fn stack_values_two_frames() -> wasmtime::Result<()> {
74     let _ = env_logger::try_init();
75 
76     for inlining in [false, true] {
77         test_stack_values(
78             r#"
79     (module
80       (import "" "host" (func))
81       (func (export "main")
82         i32.const 1
83         i32.const 2
84         call 2
85         drop)
86       (func (param i32 i32) (result i32)
87         local.get 0
88         local.get 1
89         call 0
90         i32.add))
91     "#,
92             |config| {
93                 config.compiler_inlining(inlining);
94                 if inlining {
95                     unsafe {
96                         config.cranelift_flag_set("wasmtime_inlining_intra_module", "true");
97                     }
98                 }
99             },
100             |mut caller: Caller<'_, ()>| {
101                 let stack = caller.debug_exit_frames().next().unwrap();
102                 assert_eq!(
103                     stack
104                         .wasm_function_index_and_pc(&mut caller)?
105                         .unwrap()
106                         .0
107                         .as_u32(),
108                     1
109                 );
110                 assert_eq!(
111                     stack.wasm_function_index_and_pc(&mut caller)?.unwrap().1,
112                     65
113                 );
114 
115                 assert_eq!(stack.num_locals(&mut caller)?, 2);
116                 assert_eq!(stack.num_stacks(&mut caller)?, 2);
117                 assert_eq!(stack.local(&mut caller, 0)?.unwrap_i32(), 1);
118                 assert_eq!(stack.local(&mut caller, 1)?.unwrap_i32(), 2);
119                 assert_eq!(stack.stack(&mut caller, 0)?.unwrap_i32(), 1);
120                 assert_eq!(stack.stack(&mut caller, 1)?.unwrap_i32(), 2);
121 
122                 let stack = stack.parent(&mut caller)?.unwrap();
123                 assert_eq!(
124                     stack
125                         .wasm_function_index_and_pc(&mut caller)?
126                         .unwrap()
127                         .0
128                         .as_u32(),
129                     0
130                 );
131                 assert_eq!(
132                     stack.wasm_function_index_and_pc(&mut caller)?.unwrap().1,
133                     55
134                 );
135 
136                 let stack = stack.parent(&mut caller)?;
137                 assert!(stack.is_none());
138                 Ok(())
139             },
140         )?;
141     }
142     Ok(())
143 }
144 
145 #[test]
146 #[cfg_attr(miri, ignore)]
147 fn stack_values_exceptions() -> wasmtime::Result<()> {
148     test_stack_values(
149         r#"
150     (module
151       (tag $t (param i32))
152       (import "" "host" (func))
153       (func (export "main")
154         (block $b (result i32)
155           (try_table (catch $t $b)
156             (throw $t (i32.const 42)))
157           i32.const 0)
158         (call 0)
159         (drop)))
160     "#,
161         |_config| {},
162         |mut caller: Caller<'_, ()>| {
163             let stack = caller.debug_exit_frames().next().unwrap();
164             assert_eq!(stack.num_stacks(&mut caller)?, 1);
165             assert_eq!(stack.stack(&mut caller, 0)?.unwrap_i32(), 42);
166             let stack = stack.parent(&mut caller)?;
167             assert!(stack.is_none());
168             Ok(())
169         },
170     )
171 }
172 
173 #[test]
174 #[cfg_attr(miri, ignore)]
175 fn stack_values_dead_gc_ref() -> wasmtime::Result<()> {
176     test_stack_values(
177         r#"
178     (module
179       (type $s (struct))
180       (import "" "host" (func))
181       (func (export "main")
182         (struct.new $s)
183         (call 0)
184         (drop)))
185     "#,
186         |config| {
187             config.wasm_gc(true);
188         },
189         |mut caller: Caller<'_, ()>| {
190             let stack = caller.debug_exit_frames().next().unwrap();
191             assert_eq!(stack.num_stacks(&mut caller)?, 1);
192             assert!(stack.stack(&mut caller, 0)?.unwrap_anyref().is_some());
193             let stack = stack.parent(&mut caller)?;
194             assert!(stack.is_none());
195             Ok(())
196         },
197     )
198 }
199 
200 #[test]
201 #[cfg_attr(miri, ignore)]
202 fn gc_access_during_call() -> wasmtime::Result<()> {
203     test_stack_values(
204         r#"
205     (module
206       (type $s (struct (field i32)))
207       (import "" "host" (func))
208       (func (export "main")
209         (local $l (ref null $s))
210         (local.set $l (struct.new $s (i32.const 42)))
211         (call 0)))
212     "#,
213         |config| {
214             config.wasm_gc(true);
215         },
216         |mut caller: Caller<'_, ()>| {
217             let stack = caller.debug_exit_frames().next().unwrap();
218 
219             // Do a GC while we hold the stack cursor.
220             caller.as_context_mut().gc(None).unwrap();
221 
222             assert_eq!(stack.num_stacks(&mut caller)?, 0);
223             assert_eq!(stack.num_locals(&mut caller)?, 1);
224             // Note that this struct is dead during the call, and the
225             // ref could otherwise be optimized away (no longer in the
226             // stackmap at this point); but we verify it is still
227             // alive here because it is rooted in the
228             // debug-instrumentation slot.
229             let s = stack
230                 .local(&mut caller, 0)?
231                 .unwrap_any_ref()
232                 .unwrap()
233                 .unwrap_struct(&caller)
234                 .unwrap();
235             assert_eq!(s.field(&mut caller, 0).unwrap().unwrap_i32(), 42);
236             let stack = stack.parent(&mut caller)?;
237             assert!(stack.is_none());
238             Ok(())
239         },
240     )
241 }
242 
243 #[test]
244 #[cfg_attr(miri, ignore)]
245 fn stack_values_two_activations() -> wasmtime::Result<()> {
246     let _ = env_logger::try_init();
247 
248     let mut config = Config::default();
249     config.guest_debug(true);
250     config.wasm_exceptions(true);
251     let engine = Engine::new(&config)?;
252     let module1 = Module::new(
253         &engine,
254         r#"
255     (module
256       (import "" "host1" (func (param i32 i32) (result i32)))
257       (func (export "main") (result i32)
258         i32.const 1
259         i32.const 2
260         call 0))
261     "#,
262     )?;
263     let module2 = Module::new(
264         &engine,
265         r#"
266     (module
267       (import "" "host2" (func))
268       (func (export "inner") (param i32 i32) (result i32)
269         local.get 0
270         local.get 1
271         call 0
272         i32.add))
273     "#,
274     )?;
275     let mut store = Store::new(&engine, ());
276 
277     let module1_clone = module1.clone();
278     let module2_clone = module2.clone();
279     let host2 = Func::wrap(&mut store, move |mut caller: Caller<'_, ()>| {
280         let exits = caller.debug_exit_frames().collect::<Vec<_>>();
281         assert_eq!(exits.len(), 2);
282         let stack = exits[0].clone();
283         assert_eq!(
284             stack
285                 .wasm_function_index_and_pc(&mut caller)?
286                 .unwrap()
287                 .0
288                 .as_u32(),
289             0
290         );
291         assert_eq!(
292             stack.wasm_function_index_and_pc(&mut caller)?.unwrap().1,
293             56
294         );
295         assert!(Module::same(
296             stack.module(&mut caller)?.unwrap(),
297             &module2_clone
298         ));
299         assert_eq!(stack.num_locals(&mut caller)?, 2);
300         assert_eq!(stack.num_stacks(&mut caller)?, 2);
301         assert_eq!(stack.local(&mut caller, 0)?.unwrap_i32(), 1);
302         assert_eq!(stack.local(&mut caller, 1)?.unwrap_i32(), 2);
303         assert_eq!(stack.stack(&mut caller, 0)?.unwrap_i32(), 1);
304         assert_eq!(stack.stack(&mut caller, 1)?.unwrap_i32(), 2);
305         let inner_instance = stack.instance(&mut caller)?;
306 
307         let stack = stack.parent(&mut caller)?;
308         assert!(stack.is_none());
309 
310         let stack = exits[1].clone();
311         assert_eq!(
312             stack
313                 .wasm_function_index_and_pc(&mut caller)?
314                 .unwrap()
315                 .0
316                 .as_u32(),
317             0
318         );
319         assert_eq!(
320             stack.wasm_function_index_and_pc(&mut caller)?.unwrap().1,
321             56
322         );
323         assert!(Module::same(
324             stack.module(&mut caller)?.unwrap(),
325             &module1_clone
326         ));
327         assert_eq!(stack.num_locals(&mut caller)?, 0);
328         assert_eq!(stack.num_stacks(&mut caller)?, 2);
329         assert_eq!(stack.stack(&mut caller, 0)?.unwrap_i32(), 1);
330         assert_eq!(stack.stack(&mut caller, 1)?.unwrap_i32(), 2);
331         let outer_instance = stack.instance(&mut caller)?;
332         assert_ne!(inner_instance, outer_instance);
333 
334         let stack = stack.parent(&mut caller)?;
335         assert!(stack.is_none());
336 
337         Ok(())
338     });
339 
340     let instance2 = Instance::new(&mut store, &module2, &[Extern::Func(host2)])?;
341     let inner = instance2.get_func(&mut store, "inner").unwrap();
342 
343     let host1 = Func::wrap(
344         &mut store,
345         move |mut caller: Caller<'_, ()>, a: i32, b: i32| -> i32 {
346             let mut results = [Val::I32(0)];
347             inner
348                 .call(&mut caller, &[Val::I32(a), Val::I32(b)], &mut results[..])
349                 .unwrap();
350             results[0].unwrap_i32()
351         },
352     );
353 
354     let instance1 = Instance::new(&mut store, &module1, &[Extern::Func(host1)])?;
355     let main = instance1.get_func(&mut store, "main").unwrap();
356 
357     let mut results = [Val::I32(0)];
358     main.call(&mut store, &[], &mut results)?;
359     assert_eq!(results[0].unwrap_i32(), 3);
360     Ok(())
361 }
362 
363 #[test]
364 #[cfg_attr(miri, ignore)]
365 fn debug_frames_on_store_with_no_wasm_activation() -> wasmtime::Result<()> {
366     let mut config = Config::default();
367     config.guest_debug(true);
368     let engine = Engine::new(&config)?;
369     let mut store = Store::new(&engine, ());
370     let frames = store.debug_exit_frames().collect::<Vec<_>>();
371     assert_eq!(frames.len(), 0);
372     Ok(())
373 }
374 
375 #[test]
376 #[cfg_attr(miri, ignore)]
377 fn private_entity_access() -> wasmtime::Result<()> {
378     let mut config = Config::default();
379     config.guest_debug(true);
380     config.wasm_gc(true);
381     config.gc_support(true);
382     config.wasm_exceptions(true);
383     let engine = Engine::new(&config)?;
384     let mut store = Store::new(&engine, ());
385     let module = Module::new(
386         &engine,
387         r#"
388         (module
389           (import "" "i" (global (mut i32)))
390           (import "" "f" (func (result i32)))
391           (global $g (mut i32) (i32.const 0))
392           (memory $m 1 1)
393           (table $t 10 10 i31ref)
394           (tag $tag (param f64))
395           (func (export "main")
396             ;; $g := 42
397             i32.const 42
398             global.set $g
399             ;; $m[1024] := 1
400             i32.const 1024
401             i32.const 1
402             i32.store8 $m
403             ;; $t[1] := (ref.i31 (i32.const 100))
404             i32.const 1
405             i32.const 100
406             ref.i31
407             table.set $t)
408 
409           (func (param i32)
410             local.get 0
411             global.set $g))
412         "#,
413     )?;
414 
415     let host_global = Global::new(
416         &mut store,
417         GlobalType::new(ValType::I32, Mutability::Var),
418         Val::I32(1000),
419     )?;
420     let host_func = Func::wrap(&mut store, |_caller: Caller<'_, ()>| -> i32 { 7 });
421 
422     let instance = Instance::new(
423         &mut store,
424         &module,
425         &[Extern::Global(host_global), Extern::Func(host_func)],
426     )?;
427     let func = instance.get_func(&mut store, "main").unwrap();
428     func.call(&mut store, &[], &mut [])?;
429 
430     // Nothing is exported except for `main`, yet we can still access
431     // (below).
432     let exports = instance.exports(&mut store).collect::<Vec<_>>();
433     assert_eq!(exports.len(), 1);
434     assert!(exports.into_iter().next().unwrap().into_func().is_some());
435 
436     // We can call a non-exported function.
437     let f = instance.debug_function(&mut store, 2).unwrap();
438     f.call(&mut store, &[Val::I32(1234)], &mut [])?;
439 
440     let g = instance.debug_global(&mut store, 1).unwrap();
441     assert_eq!(g.get(&mut store).unwrap_i32(), 1234);
442 
443     let m = instance.debug_memory(&mut store, 0).unwrap();
444     assert_eq!(m.data(&mut store)[1024], 1);
445 
446     let t = instance.debug_table(&mut store, 0).unwrap();
447     let t_val = t.get(&mut store, 1).unwrap();
448     let t_val = t_val.as_any().unwrap().unwrap().unwrap_i31(&store).unwrap();
449     assert_eq!(t_val.get_u32(), 100);
450 
451     let tag = instance.debug_tag(&mut store, 0).unwrap();
452     assert!(matches!(
453         tag.ty(&store).ty().param(0).unwrap(),
454         ValType::F64
455     ));
456 
457     // Check that we can access an imported global in the instance's
458     // index space.
459     let host_global_import = instance.debug_global(&mut store, 0).unwrap();
460     assert_eq!(host_global_import.get(&mut store).unwrap_i32(), 1000);
461 
462     // Check that we can call an imported function in the instance's
463     // index space.
464     let host_func_import = instance.debug_function(&mut store, 0).unwrap();
465     let mut results = [Val::I32(0)];
466     host_func_import.call(&mut store, &[], &mut results[..])?;
467     assert_eq!(results[0].unwrap_i32(), 7);
468 
469     // Check that out-of-bounds returns `None` rather than panic'ing.
470     assert!(instance.debug_global(&mut store, 2).is_none());
471 
472     Ok(())
473 }
474 
475 #[test]
476 #[cfg_attr(miri, ignore)]
477 #[cfg(target_pointer_width = "64")] // Threads not supported on 32-bit systems.
478 fn private_entity_access_shared_memory() -> wasmtime::Result<()> {
479     let mut config = Config::default();
480     config.guest_debug(true);
481     config.shared_memory(true);
482     config.wasm_threads(true);
483     let engine = Engine::new(&config)?;
484     let mut store = Store::new(&engine, ());
485     let module = Module::new(
486         &engine,
487         r#"
488         (module
489           (memory 1 1 shared))
490         "#,
491     )?;
492 
493     let instance = Instance::new(&mut store, &module, &[])?;
494 
495     let m = instance.debug_shared_memory(&mut store, 0).unwrap();
496     let unsafe_cell = &m.data()[1024];
497     assert_eq!(unsafe { *unsafe_cell.get() }, 0);
498 
499     Ok(())
500 }
501 
502 macro_rules! debug_event_checker {
503     ($ty:tt,
504      $store:tt,
505      $(
506          { $i:expr ; $pat:pat => $body:tt }
507      ),*)
508     =>
509     {
510         #[derive(Clone)]
511         struct $ty(Arc<AtomicUsize>);
512         impl $ty {
513             fn new_and_counter() -> (Self, Arc<AtomicUsize>) {
514                 let counter = Arc::new(AtomicUsize::new(0));
515                 let counter_clone = counter.clone();
516                 ($ty(counter), counter_clone)
517             }
518         }
519         impl DebugHandler for $ty {
520             type Data = ();
521             fn handle(
522                 &self,
523                 #[allow(unused_variables, reason = "macro rules")]
524                 #[allow(unused_mut, reason = "macro rules")]
525                 mut $store: StoreContextMut<'_, ()>,
526                 event: DebugEvent<'_>,
527             ) -> impl Future<Output = ()> + Send {
528                 let step = self.0.fetch_add(1, Ordering::Relaxed);
529                 async move {
530                     if false {}
531                     $(
532                         else if step == $i {
533                             match event {
534                                 $pat => {
535                                     $body;
536                                 }
537                                 _ => panic!("Incorrect event"),
538                             }
539                         }
540                     )*
541                     else {
542                         panic!("Too many steps");
543                     }
544                 }
545             }
546         }
547     }
548 }
549 
550 #[tokio::test]
551 #[cfg_attr(miri, ignore)]
552 async fn uncaught_exception_events() -> wasmtime::Result<()> {
553     let _ = env_logger::try_init();
554 
555     let (module, mut store) = get_module_and_store(
556         |config| {
557             config.wasm_exceptions(true);
558         },
559         r#"
560     (module
561       (tag $t (param i32))
562       (func (export "main")
563         call 1)
564       (func
565         (local $i i32)
566         (local.set $i (i32.const 100))
567         (throw $t (i32.const 42))))
568     "#,
569     )?;
570 
571     debug_event_checker!(
572         D, store,
573         { 0 ;
574           wasmtime::DebugEvent::UncaughtExceptionThrown(e) => {
575               assert_eq!(e.field(&mut store, 0).unwrap().unwrap_i32(), 42);
576               let stack = store.debug_exit_frames().next().unwrap();
577               assert_eq!(stack.num_locals(&mut store).unwrap(), 1);
578               assert_eq!(stack.local(&mut store, 0).unwrap().unwrap_i32(), 100);
579               let stack = stack.parent(&mut store).unwrap().unwrap();
580               let stack = stack.parent(&mut store).unwrap();
581               assert!(stack.is_none());
582           }
583         }
584     );
585 
586     let (handler, counter) = D::new_and_counter();
587     store.set_debug_handler(handler);
588 
589     let instance = Instance::new_async(&mut store, &module, &[]).await?;
590     let func = instance.get_func(&mut store, "main").unwrap();
591     let mut results = [];
592     let result = func.call_async(&mut store, &[], &mut results).await;
593     assert!(result.is_err()); // Uncaught exception.
594     assert_eq!(counter.load(Ordering::Relaxed), 1);
595 
596     Ok(())
597 }
598 
599 #[tokio::test]
600 #[cfg_attr(miri, ignore)]
601 async fn caught_exception_events() -> wasmtime::Result<()> {
602     let _ = env_logger::try_init();
603 
604     let (module, mut store) = get_module_and_store(
605         |config| {
606             config.wasm_exceptions(true);
607         },
608         r#"
609     (module
610       (tag $t (param i32))
611       (func (export "main")
612         (block $b (result i32)
613           (try_table (catch $t $b)
614             call 1)
615           i32.const 0)
616         drop)
617       (func
618         (local $i i32)
619         (local.set $i (i32.const 100))
620         (throw $t (i32.const 42))))
621     "#,
622     )?;
623 
624     debug_event_checker!(
625         D, store,
626         { 0 ;
627           wasmtime::DebugEvent::CaughtExceptionThrown(e) => {
628               assert_eq!(e.field(&mut store, 0).unwrap().unwrap_i32(), 42);
629               let stack = store.debug_exit_frames().next().unwrap();
630               assert_eq!(stack.num_locals(&mut store).unwrap(), 1);
631               assert_eq!(stack.local(&mut store, 0).unwrap().unwrap_i32(), 100);
632               let stack = stack.parent(&mut store).unwrap().unwrap();
633               let stack = stack.parent(&mut store).unwrap();
634               assert!(stack.is_none());
635           }
636         }
637     );
638 
639     let (handler, counter) = D::new_and_counter();
640     store.set_debug_handler(handler);
641 
642     let instance = Instance::new_async(&mut store, &module, &[]).await?;
643     let func = instance.get_func(&mut store, "main").unwrap();
644     let mut results = [];
645     func.call_async(&mut store, &[], &mut results).await?;
646     assert_eq!(counter.load(Ordering::Relaxed), 1);
647 
648     Ok(())
649 }
650 
651 #[tokio::test]
652 #[cfg_attr(miri, ignore)]
653 async fn hostcall_trap_events() -> wasmtime::Result<()> {
654     let _ = env_logger::try_init();
655 
656     let (module, mut store) = get_module_and_store(
657         |config| {
658             config.wasm_exceptions(true);
659         },
660         r#"
661     (module
662       (func (export "main")
663         i32.const 0
664         i32.const 0
665         i32.div_u
666         drop))
667     "#,
668     )?;
669 
670     debug_event_checker!(
671         D, store,
672         { 0 ;
673           wasmtime::DebugEvent::Trap(wasmtime_environ::Trap::IntegerDivisionByZero) => {}
674         }
675     );
676 
677     let (handler, counter) = D::new_and_counter();
678     store.set_debug_handler(handler);
679 
680     let instance = Instance::new_async(&mut store, &module, &[]).await?;
681     let func = instance.get_func(&mut store, "main").unwrap();
682     let mut results = [];
683     let result = func.call_async(&mut store, &[], &mut results).await;
684     assert!(result.is_err()); // Uncaught trap.
685     assert_eq!(counter.load(Ordering::Relaxed), 1);
686 
687     Ok(())
688 }
689 
690 #[tokio::test]
691 #[cfg_attr(miri, ignore)]
692 async fn hostcall_error_events() -> wasmtime::Result<()> {
693     let _ = env_logger::try_init();
694 
695     let (module, mut store) = get_module_and_store(
696         |config| {
697             config.wasm_exceptions(true);
698         },
699         r#"
700     (module
701       (import "" "do_a_trap" (func))
702       (func (export "main")
703         call 0))
704     "#,
705     )?;
706 
707     debug_event_checker!(
708         D, store,
709         { 0 ;
710           wasmtime::DebugEvent::HostcallError(e) => {
711               assert!(format!("{e:?}").contains("secret error message"));
712           }
713         }
714     );
715 
716     let (handler, counter) = D::new_and_counter();
717     store.set_debug_handler(handler);
718 
719     let do_a_trap = Func::wrap(
720         &mut store,
721         |_caller: Caller<'_, ()>| -> wasmtime::Result<()> {
722             Err(wasmtime::format_err!("secret error message"))
723         },
724     );
725     let instance = Instance::new_async(&mut store, &module, &[Extern::Func(do_a_trap)]).await?;
726     let func = instance.get_func(&mut store, "main").unwrap();
727     let mut results = [];
728     let result = func.call_async(&mut store, &[], &mut results).await;
729     assert!(result.is_err()); // Uncaught trap.
730     assert_eq!(counter.load(Ordering::Relaxed), 1);
731     Ok(())
732 }
733 
734 #[tokio::test]
735 #[cfg_attr(miri, ignore)]
736 async fn breakpoint_events() -> wasmtime::Result<()> {
737     let _ = env_logger::try_init();
738 
739     let (module, mut store) = get_module_and_store(
740         |config| {
741             config.wasm_exceptions(true);
742         },
743         r#"
744     (module
745       (func (export "main") (param i32 i32) (result i32)
746         local.get 0
747         local.get 1
748         i32.add))
749     "#,
750     )?;
751 
752     debug_event_checker!(
753         D, store,
754         { 0 ;
755           wasmtime::DebugEvent::Breakpoint => {
756               let stack = store.debug_exit_frames().next().unwrap();
757               assert_eq!(stack.num_locals(&mut store).unwrap(), 2);
758               assert_eq!(stack.local(&mut store, 0).unwrap().unwrap_i32(), 1);
759               assert_eq!(stack.local(&mut store, 1).unwrap().unwrap_i32(), 2);
760               let (func, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
761               assert_eq!(func.as_u32(), 0);
762               assert_eq!(pc, 0x28);
763               let stack = stack.parent(&mut store).unwrap();
764               assert!(stack.is_none());
765           }
766         }
767     );
768 
769     let (handler, counter) = D::new_and_counter();
770     store.set_debug_handler(handler);
771     store
772         .edit_breakpoints()
773         .unwrap()
774         .add_breakpoint(&module, 0x28)?;
775 
776     let instance = Instance::new_async(&mut store, &module, &[]).await?;
777     let func = instance.get_func(&mut store, "main").unwrap();
778     let mut results = [Val::I32(0)];
779     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
780         .await?;
781     assert_eq!(counter.load(Ordering::Relaxed), 1);
782     assert_eq!(results[0].unwrap_i32(), 3);
783 
784     let breakpoints = store.breakpoints().unwrap().collect::<Vec<_>>();
785     assert_eq!(breakpoints.len(), 1);
786     assert!(Module::same(&breakpoints[0].module, &module));
787     assert_eq!(breakpoints[0].pc, 0x28);
788 
789     store
790         .edit_breakpoints()
791         .unwrap()
792         .remove_breakpoint(&module, 0x28)?;
793     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
794         .await?;
795     assert_eq!(counter.load(Ordering::Relaxed), 1); // Should not have incremented from above.
796     assert_eq!(results[0].unwrap_i32(), 3);
797 
798     // Enable single-step mode (on top of the breakpoint already enabled).
799     assert!(!store.is_single_step());
800     store.edit_breakpoints().unwrap().single_step(true).unwrap();
801     assert!(store.is_single_step());
802 
803     debug_event_checker!(
804         D2, store,
805         { 0 ;
806           wasmtime::DebugEvent::Breakpoint => {
807               let stack = store.debug_exit_frames().next().unwrap();
808               let (_, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
809               assert_eq!(pc, 0x24);
810           }
811         },
812         {
813           1 ;
814           wasmtime::DebugEvent::Breakpoint => {
815               let stack = store.debug_exit_frames().next().unwrap();
816               let (_, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
817               assert_eq!(pc, 0x26);
818           }
819         },
820         {
821           2 ;
822           wasmtime::DebugEvent::Breakpoint => {
823               let stack = store.debug_exit_frames().next().unwrap();
824               let (_, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
825               assert_eq!(pc, 0x28);
826           }
827         },
828         {
829           3 ;
830           wasmtime::DebugEvent::Breakpoint => {
831               let stack = store.debug_exit_frames().next().unwrap();
832               let (_, pc) = stack.wasm_function_index_and_pc(&mut store).unwrap().unwrap();
833               assert_eq!(pc, 0x29);
834           }
835         }
836     );
837 
838     let (handler, counter) = D2::new_and_counter();
839     store.set_debug_handler(handler);
840 
841     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
842         .await?;
843     assert_eq!(counter.load(Ordering::Relaxed), 4);
844 
845     // Re-enable individual breakpoint.
846     store
847         .edit_breakpoints()
848         .unwrap()
849         .add_breakpoint(&module, 0x28)
850         .unwrap();
851 
852     // Now disable single-stepping. The single breakpoint set above
853     // should still remain.
854     store
855         .edit_breakpoints()
856         .unwrap()
857         .single_step(false)
858         .unwrap();
859 
860     let (handler, counter) = D::new_and_counter();
861     store.set_debug_handler(handler);
862 
863     func.call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
864         .await?;
865     assert_eq!(counter.load(Ordering::Relaxed), 1);
866 
867     Ok(())
868 }
869 
870 #[tokio::test]
871 #[cfg_attr(miri, ignore)]
872 async fn breakpoints_in_inlined_code() -> wasmtime::Result<()> {
873     let _ = env_logger::try_init();
874 
875     let (module, mut store) = get_module_and_store(
876         |config| {
877             config.wasm_exceptions(true);
878             config.compiler_inlining(true);
879             unsafe {
880                 config.cranelift_flag_set("wasmtime_inlining_intra_module", "true");
881             }
882         },
883         r#"
884     (module
885       (func $f (export "f") (param i32 i32) (result i32)
886         local.get 0
887         local.get 1
888         i32.add)
889 
890       (func (export "main") (param i32 i32) (result i32)
891         local.get 0
892         local.get 1
893         call $f))
894     "#,
895     )?;
896 
897     debug_event_checker!(
898         D, store,
899         { 0 ;
900           wasmtime::DebugEvent::Breakpoint => {}
901         },
902         { 1 ;
903           wasmtime::DebugEvent::Breakpoint => {}
904         }
905     );
906 
907     let (handler, counter) = D::new_and_counter();
908     store.set_debug_handler(handler);
909     store
910         .edit_breakpoints()
911         .unwrap()
912         .add_breakpoint(&module, 0x2d)?; // `i32.add` in `$f`.
913 
914     let instance = Instance::new_async(&mut store, &module, &[]).await?;
915     let func_main = instance.get_func(&mut store, "main").unwrap();
916     let func_f = instance.get_func(&mut store, "f").unwrap();
917     let mut results = [Val::I32(0)];
918     // Breakpoint in `$f` should have been hit in `main` even if it
919     // was inlined.
920     func_main
921         .call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
922         .await?;
923     assert_eq!(counter.load(Ordering::Relaxed), 1);
924     assert_eq!(results[0].unwrap_i32(), 3);
925 
926     // Breakpoint in `$f` should be hit when called directly, too.
927     func_f
928         .call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
929         .await?;
930     assert_eq!(counter.load(Ordering::Relaxed), 2);
931     assert_eq!(results[0].unwrap_i32(), 3);
932 
933     Ok(())
934 }
935 
936 #[tokio::test]
937 #[cfg_attr(miri, ignore)]
938 async fn epoch_events() -> wasmtime::Result<()> {
939     let _ = env_logger::try_init();
940 
941     let (module, mut store) = get_module_and_store(
942         |config| {
943             config.epoch_interruption(true);
944         },
945         r#"
946     (module
947       (func $f (export "f") (param i32 i32) (result i32)
948         local.get 0
949         local.get 1
950         i32.add))
951     "#,
952     )?;
953 
954     debug_event_checker!(
955         D, store,
956         { 0 ;
957           wasmtime::DebugEvent::EpochYield => {}
958         }
959     );
960 
961     let (handler, counter) = D::new_and_counter();
962     store.set_debug_handler(handler);
963 
964     store.set_epoch_deadline(1);
965     store.epoch_deadline_async_yield_and_update(1);
966     store.engine().increment_epoch();
967 
968     let instance = Instance::new_async(&mut store, &module, &[]).await?;
969     let func_f = instance.get_func(&mut store, "f").unwrap();
970     let mut results = [Val::I32(0)];
971     func_f
972         .call_async(&mut store, &[Val::I32(1), Val::I32(2)], &mut results)
973         .await?;
974     assert_eq!(counter.load(Ordering::Relaxed), 1);
975     assert_eq!(results[0].unwrap_i32(), 3);
976 
977     Ok(())
978 }
979 
980 #[tokio::test]
981 #[cfg_attr(miri, ignore)]
982 async fn invalidated_frame_handles() -> wasmtime::Result<()> {
983     let (module, mut store) = get_module_and_store(
984         |_config| {},
985         r#"
986     (module
987       (import "" "" (func))
988       (func (export "main")
989         (local i32 i32)
990         i32.const 1
991         local.set 0
992         i32.const 2
993         local.set 1
994         call 2
995         call 0)
996       (func
997         (local i32 i32)
998         i32.const 3
999         local.set 0
1000         i32.const 4
1001         local.set 1
1002         call 0))
1003         "#,
1004     )?;
1005 
1006     let handle: Arc<Mutex<Option<FrameHandle>>> = Arc::new(Mutex::new(None));
1007 
1008     let hostfunc = Func::wrap_async(&mut store, move |mut caller, _args: ()| {
1009         let handle = handle.clone();
1010         Box::new(async move {
1011             let frame = handle.lock().unwrap().take();
1012             if let Some(frame) = frame {
1013                 // Ensure that the handle has been invalidated.
1014                 assert!(!frame.is_valid(&mut caller));
1015                 // Ensure that attempts to fetch data from the frame
1016                 // fail with a clean `Err`, not a panic or crash.
1017                 let result = frame.wasm_function_index_and_pc(&mut caller);
1018                 assert!(result.is_err());
1019                 // Ensure that we can get a new frame handle and use it.
1020                 let frame = caller.debug_exit_frames().next().unwrap();
1021                 assert_eq!(frame.num_locals(&mut caller)?, 2);
1022                 assert_eq!(frame.local(&mut caller, 0)?.unwrap_i32(), 1);
1023                 assert_eq!(frame.local(&mut caller, 1)?.unwrap_i32(), 2);
1024             } else {
1025                 let frame = caller.debug_exit_frames().next().unwrap();
1026                 assert_eq!(frame.num_locals(&mut caller)?, 2);
1027                 assert_eq!(frame.local(&mut caller, 0)?.unwrap_i32(), 3);
1028                 assert_eq!(frame.local(&mut caller, 1)?.unwrap_i32(), 4);
1029                 *handle.lock().unwrap() = Some(frame);
1030             }
1031             Ok(())
1032         })
1033     });
1034 
1035     let instance = Instance::new_async(&mut store, &module, &[Extern::Func(hostfunc)]).await?;
1036     let main = instance.get_func(&mut store, "main").unwrap();
1037     main.call_async(&mut store, &[], &mut []).await?;
1038 
1039     Ok(())
1040 }
1041 
1042 #[tokio::test]
1043 #[cfg_attr(miri, ignore)]
1044 async fn invalidated_frame_handles_in_dropped_future() -> wasmtime::Result<()> {
1045     let (module, mut store) = get_module_and_store(
1046         |_config| {},
1047         r#"
1048     (module
1049       (import "" "" (func))
1050       (func (export "main")
1051         call 0))
1052         "#,
1053     )?;
1054 
1055     let handle: Arc<Mutex<Option<FrameHandle>>> = Arc::new(Mutex::new(None));
1056     let handle_clone = handle.clone();
1057 
1058     let hostfunc = Func::wrap_async(&mut store, move |mut caller, _args: ()| {
1059         let handle_clone = handle_clone.clone();
1060         Box::new(async move {
1061             let frame = caller.debug_exit_frames().next().unwrap();
1062             *handle_clone.lock().unwrap() = Some(frame);
1063             tokio::task::yield_now().await;
1064         })
1065     });
1066 
1067     let instance = Instance::new_async(&mut store, &module, &[Extern::Func(hostfunc)]).await?;
1068     let main = instance.get_func(&mut store, "main").unwrap();
1069     let future = Box::pin(main.call_async(&mut store, &[], &mut []));
1070 
1071     // Poll once, then drop.
1072     let poll_once = PollOnce::new(future);
1073     let future = poll_once.await;
1074 
1075     drop(future);
1076 
1077     // The frame handle should now be invalid.
1078     let mut handle = handle.lock().unwrap();
1079     let frame = handle.take().unwrap();
1080     assert!(!frame.is_valid(&mut store));
1081 
1082     Ok(())
1083 }
1084