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     /// The `zeroed` parameter is whether the stack's memory should be zeroed,
24     /// as a defense-in-depth measure.
25     ///
26     /// Note there should be at least one guard page of protected memory at the bottom
27     /// of the stack to catch potential stack overflow scenarios. Additionally, stacks should be
28     /// page aligned and zero filled.
29     fn new_stack(&self, size: usize, zeroed: bool) -> Result<Box<dyn StackMemory>, Error>;
30 }
31 
32 #[derive(Clone)]
33 pub(crate) struct StackCreatorProxy(pub Arc<dyn StackCreator>);
34 
35 unsafe impl RuntimeFiberStackCreator for StackCreatorProxy {
36     fn new_stack(&self, size: usize, zeroed: bool) -> Result<Box<dyn RuntimeFiberStack>, Error> {
37         let stack = self.0.new_stack(size, zeroed)?;
38         Ok(Box::new(FiberStackProxy(stack)) as Box<dyn RuntimeFiberStack>)
39     }
40 }
41 
42 /// A stack memory. This trait provides an interface for raw memory buffers
43 /// which are used by wasmtime inside of stacks which wasmtime executes
44 /// WebAssembly in for async support. By implementing this trait together
45 /// with StackCreator, one can supply wasmtime with custom allocated host
46 /// managed stacks.
47 ///
48 /// # Safety
49 ///
50 /// The memory should be page aligned and a multiple of page size.
51 /// To prevent possible silent overflows, the memory should be protected by a
52 /// guard page. Additionally the safety concerns explained in ['Memory'], for
53 /// accessing the memory apply here as well.
54 ///
55 /// Note that this is a relatively new and experimental feature and it is
56 /// recommended to be familiar with wasmtime runtime code to use it.
57 pub unsafe trait StackMemory: Send + Sync {
58     /// The top of the allocated stack.
59     ///
60     /// This address should be page aligned.
61     fn top(&self) -> *mut u8;
62     /// The range of where this stack resides in memory, excluding guard pages.
63     fn range(&self) -> Range<usize>;
64     /// The range of memory where the guard region of this stack resides.
65     fn guard_range(&self) -> Range<*mut u8>;
66 }
67 
68 pub(crate) struct FiberStackProxy(pub Box<dyn StackMemory>);
69 
70 unsafe impl RuntimeFiberStack for FiberStackProxy {
71     fn top(&self) -> *mut u8 {
72         self.0.top()
73     }
74 
75     fn range(&self) -> Range<usize> {
76         self.0.range()
77     }
78 
79     fn guard_range(&self) -> Range<*mut u8> {
80         self.0.guard_range()
81     }
82 }
83