1 #![no_std]
2 
3 #[macro_use]
4 extern crate alloc;
5 
6 use alloc::string::ToString;
7 use anyhow::Result;
8 use core::ptr;
9 use wasmtime::{Engine, Instance, Linker, Module, Store};
10 
11 mod allocator;
12 mod panic;
13 
14 #[cfg(feature = "wasi")]
15 mod wasi;
16 
17 /// Entrypoint of this embedding.
18 ///
19 /// This takes a number of parameters which are the precompiled module AOT
20 /// images that are run for each of the various tests below. The first parameter
21 /// is also where to put an error string, if any, if anything fails.
22 #[unsafe(no_mangle)]
23 pub unsafe extern "C" fn run(
24     error_buf: *mut u8,
25     error_size: usize,
26     smoke_module: *const u8,
27     smoke_size: usize,
28     simple_add_module: *const u8,
29     simple_add_size: usize,
30     simple_host_fn_module: *const u8,
31     simple_host_fn_size: usize,
32 ) -> usize {
33     unsafe {
34         let buf = core::slice::from_raw_parts_mut(error_buf, error_size);
35         let smoke = core::slice::from_raw_parts(smoke_module, smoke_size);
36         let simple_add = core::slice::from_raw_parts(simple_add_module, simple_add_size);
37         let simple_host_fn =
38             core::slice::from_raw_parts(simple_host_fn_module, simple_host_fn_size);
39         match run_result(smoke, simple_add, simple_host_fn) {
40             Ok(()) => 0,
41             Err(e) => {
42                 let msg = format!("{e:?}");
43                 let len = buf.len().min(msg.len());
44                 buf[..len].copy_from_slice(&msg.as_bytes()[..len]);
45                 len
46             }
47         }
48     }
49 }
50 
51 fn run_result(
52     smoke_module: &[u8],
53     simple_add_module: &[u8],
54     simple_host_fn_module: &[u8],
55 ) -> Result<()> {
56     smoke(smoke_module)?;
57     simple_add(simple_add_module)?;
58     simple_host_fn(simple_host_fn_module)?;
59     Ok(())
60 }
61 
62 fn smoke(module: &[u8]) -> Result<()> {
63     let engine = Engine::default();
64     let module = match deserialize(&engine, module)? {
65         Some(module) => module,
66         None => return Ok(()),
67     };
68     Instance::new(&mut Store::new(&engine, ()), &module, &[])?;
69     Ok(())
70 }
71 
72 fn simple_add(module: &[u8]) -> Result<()> {
73     let engine = Engine::default();
74     let module = match deserialize(&engine, module)? {
75         Some(module) => module,
76         None => return Ok(()),
77     };
78     let mut store = Store::new(&engine, ());
79     let instance = Linker::new(&engine).instantiate(&mut store, &module)?;
80     let func = instance.get_typed_func::<(u32, u32), u32>(&mut store, "add")?;
81     assert_eq!(func.call(&mut store, (2, 3))?, 5);
82     Ok(())
83 }
84 
85 fn simple_host_fn(module: &[u8]) -> Result<()> {
86     let engine = Engine::default();
87     let module = match deserialize(&engine, module)? {
88         Some(module) => module,
89         None => return Ok(()),
90     };
91     let mut linker = Linker::<()>::new(&engine);
92     linker.func_wrap("host", "multiply", |a: u32, b: u32| a.saturating_mul(b))?;
93     let mut store = Store::new(&engine, ());
94     let instance = linker.instantiate(&mut store, &module)?;
95     let func = instance.get_typed_func::<(u32, u32, u32), u32>(&mut store, "add_and_mul")?;
96     assert_eq!(func.call(&mut store, (2, 3, 4))?, 10);
97     Ok(())
98 }
99 
100 fn deserialize(engine: &Engine, module: &[u8]) -> Result<Option<Module>> {
101     let result = if cfg!(feature = "custom") {
102         // If a custom virtual memory system is in use use the raw `deserialize`
103         // API to let Wasmtime handle publishing the executable and such.
104         unsafe { Module::deserialize(engine, module) }
105     } else {
106         // NOTE: deserialize_raw avoids creating a copy of the module code. See
107         // the safety notes before using in your embedding.
108         //
109         // Also note that this will only work for native code with a custom code
110         // publisher which isn't configured in this example. Such custom code
111         // publisher will need to handle making this executable for example.
112         let memory_ptr = ptr::slice_from_raw_parts(module.as_ptr(), module.len());
113         let module_memory = ptr::NonNull::new(memory_ptr.cast_mut()).unwrap();
114         unsafe { Module::deserialize_raw(engine, module_memory) }
115     };
116     match result {
117         Ok(module) => Ok(Some(module)),
118         Err(e) => {
119             // Currently if custom signals/virtual memory are disabled then this
120             // example is expected to fail to load since loading native code
121             // requires virtual memory. In the future this will go away as when
122             // signals-based-traps is disabled then that means that the
123             // interpreter should be used which should work here.
124             if !cfg!(feature = "custom")
125                 && e.to_string()
126                     .contains("requires virtual memory to be enabled")
127             {
128                 Ok(None)
129             } else {
130                 Err(e)
131             }
132         }
133     }
134 }
135