1 use crate::prelude::*;
2 use alloc::sync::Arc;
3 use core::ops::Range;
4 use wasmtime_fiber::{RuntimeFiberStack, RuntimeFiberStackCreator};
5 
6 /// A stack creator. Can be used to provide a stack creator to wasmtime
7 /// which supplies stacks for async support.
8 ///
9 /// # Safety
10 ///
11 /// This trait is unsafe, as memory safety depends on a proper implementation
12 /// of memory management. Stacks created by the StackCreator should always be
13 /// treated as owned by an wasmtime instance, and any modification of them
14 /// outside of wasmtime invoked routines is unsafe and may lead to corruption.
15 ///
16 /// Note that this is a relatively new and experimental feature and it is
17 /// recommended to be familiar with wasmtime runtime code to use it.
18 pub unsafe trait StackCreator: Send + Sync {
19     /// Create a new `StackMemory` object with the specified size.
20     ///
21     /// The `size` parameter is the expected size of the stack without any guard pages.
22     ///
23     /// Note there should be at least one guard page of protected memory at the bottom
24     /// of the stack to catch potential stack overflow scenarios. Additionally, stacks should be
25     /// page aligned and zero filled.
26     fn new_stack(&self, size: usize) -> Result<Box<dyn StackMemory>, Error>;
27 }
28 
29 #[derive(Clone)]
30 pub(crate) struct StackCreatorProxy(pub Arc<dyn StackCreator>);
31 
32 unsafe impl RuntimeFiberStackCreator for StackCreatorProxy {
33     fn new_stack(&self, size: usize) -> Result<Box<dyn RuntimeFiberStack>, Error> {
34         let stack = self.0.new_stack(size)?;
35         Ok(Box::new(FiberStackProxy(stack)) as Box<dyn RuntimeFiberStack>)
36     }
37 }
38 
39 /// A stack memory. This trait provides an interface for raw memory buffers
40 /// which are used by wasmtime inside of stacks which wasmtime executes
41 /// WebAssembly in for async support. By implementing this trait together
42 /// with StackCreator, one can supply wasmtime with custom allocated host
43 /// managed stacks.
44 ///
45 /// # Safety
46 ///
47 /// The memory should be page aligned and a multiple of page size.
48 /// To prevent possible silent overflows, the memory should be protected by a
49 /// guard page. Additionally the safety concerns explained in ['Memory'], for
50 /// accessing the memory apply here as well.
51 ///
52 /// Note that this is a relatively new and experimental feature and it is
53 /// recommended to be familiar with wasmtime runtime code to use it.
54 pub unsafe trait StackMemory: Send + Sync {
55     /// The top of the allocated stack.
56     ///
57     /// This address should be page aligned.
58     fn top(&self) -> *mut u8;
59     /// The range of where this stack resides in memory, excluding guard pages.
60     fn range(&self) -> Range<usize>;
61     /// The range of memory where the guard region of this stack resides.
62     fn guard_range(&self) -> Range<*mut u8>;
63 }
64 
65 pub(crate) struct FiberStackProxy(pub Box<dyn StackMemory>);
66 
67 unsafe impl RuntimeFiberStack for FiberStackProxy {
68     fn top(&self) -> *mut u8 {
69         self.0.top()
70     }
71 
72     fn range(&self) -> Range<usize> {
73         self.0.range()
74     }
75 
76     fn guard_range(&self) -> Range<*mut u8> {
77         self.0.guard_range()
78     }
79 }
80