1#![no_std]
2
3#[macro_use]
4extern crate alloc;
5
6use alloc::string::ToString;
7use anyhow::{Result, ensure};
8use core::ptr;
9use wasmtime::{Config, Engine, Instance, Linker, Module, Store};
10
11mod allocator;
12mod panic;
13
14#[cfg(feature = "wasi")]
15mod wasi;
16
17#[unsafe(no_mangle)]
23pub 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 simple_floats_module: *const u8,
33 simple_floats_size: usize,
34) -> usize {
35 unsafe {
36 let buf = core::slice::from_raw_parts_mut(error_buf, error_size);
37 let smoke = core::slice::from_raw_parts(smoke_module, smoke_size);
38 let simple_add = core::slice::from_raw_parts(simple_add_module, simple_add_size);
39 let simple_host_fn =
40 core::slice::from_raw_parts(simple_host_fn_module, simple_host_fn_size);
41 let simple_floats = core::slice::from_raw_parts(simple_floats_module, simple_floats_size);
42 match run_result(smoke, simple_add, simple_host_fn, simple_floats) {
43 Ok(()) => 0,
44 Err(e) => {
45 let msg = format!("{e:?}");
46 let len = buf.len().min(msg.len());
47 buf[..len].copy_from_slice(&msg.as_bytes()[..len]);
48 len
49 }
50 }
51 }
52}
53
54fn run_result(
55 smoke_module: &[u8],
56 simple_add_module: &[u8],
57 simple_host_fn_module: &[u8],
58 simple_floats_module: &[u8],
59) -> Result<()> {
60 smoke(smoke_module)?;
61 simple_add(simple_add_module)?;
62 simple_host_fn(simple_host_fn_module)?;
63 simple_floats(simple_floats_module)?;
64 Ok(())
65}
66
67fn config() -> Config {
68 let mut config = Config::new();
69 let _ = &mut config;
70
71 #[cfg(target_arch = "x86_64")]
72 {
73 unsafe {
79 config.x86_float_abi_ok(true);
80 }
81
82 unsafe {
91 config.detect_host_feature(move |feature| {
92 let id = raw_cpuid::CpuId::new();
93 match feature {
94 "sse3" => Some(id.get_feature_info()?.has_sse3()),
95 "ssse3" => Some(id.get_feature_info()?.has_sse3()),
96 "sse4.1" => Some(id.get_feature_info()?.has_sse41()),
97 "sse4.2" => Some(id.get_feature_info()?.has_sse42()),
98 "fma" => Some(id.get_feature_info()?.has_fma()),
99 _ => None,
100 }
101 });
102 }
103 }
104
105 config
106}
107
108fn smoke(module: &[u8]) -> Result<()> {
109 let engine = Engine::new(&config())?;
110 let module = match deserialize(&engine, module)? {
111 Some(module) => module,
112 None => return Ok(()),
113 };
114 Instance::new(&mut Store::new(&engine, ()), &module, &[])?;
115 Ok(())
116}
117
118fn simple_add(module: &[u8]) -> Result<()> {
119 let engine = Engine::new(&config())?;
120 let module = match deserialize(&engine, module)? {
121 Some(module) => module,
122 None => return Ok(()),
123 };
124 let mut store = Store::new(&engine, ());
125 let instance = Linker::new(&engine).instantiate(&mut store, &module)?;
126 let func = instance.get_typed_func::<(u32, u32), u32>(&mut store, "add")?;
127 ensure!(func.call(&mut store, (2, 3))? == 5);
128 Ok(())
129}
130
131fn simple_host_fn(module: &[u8]) -> Result<()> {
132 let engine = Engine::new(&config())?;
133 let module = match deserialize(&engine, module)? {
134 Some(module) => module,
135 None => return Ok(()),
136 };
137 let mut linker = Linker::<()>::new(&engine);
138 linker.func_wrap("host", "multiply", |a: u32, b: u32| a.saturating_mul(b))?;
139 let mut store = Store::new(&engine, ());
140 let instance = linker.instantiate(&mut store, &module)?;
141 let func = instance.get_typed_func::<(u32, u32, u32), u32>(&mut store, "add_and_mul")?;
142 ensure!(func.call(&mut store, (2, 3, 4))? == 10);
143 Ok(())
144}
145
146fn simple_floats(module: &[u8]) -> Result<()> {
147 let engine = Engine::new(&config())?;
148 let module = match deserialize(&engine, module)? {
149 Some(module) => module,
150 None => return Ok(()),
151 };
152 let mut store = Store::new(&engine, ());
153 let instance = Linker::new(&engine).instantiate(&mut store, &module)?;
154 let func = instance.get_typed_func::<(f32, f32), f32>(&mut store, "frob")?;
155 ensure!(func.call(&mut store, (1.4, 3.2))? == 5.);
156 Ok(())
157}
158
159fn deserialize(engine: &Engine, module: &[u8]) -> Result<Option<Module>> {
160 let result = if cfg!(feature = "custom") {
161 unsafe { Module::deserialize(engine, module) }
164 } else {
165 let memory_ptr = ptr::slice_from_raw_parts(module.as_ptr(), module.len());
172 let module_memory = ptr::NonNull::new(memory_ptr.cast_mut()).unwrap();
173 unsafe { Module::deserialize_raw(engine, module_memory) }
174 };
175 match result {
176 Ok(module) => Ok(Some(module)),
177 Err(e) => {
178 if !cfg!(feature = "custom")
184 && e.to_string()
185 .contains("requires virtual memory to be enabled")
186 {
187 Ok(None)
188 } else {
189 Err(e)
190 }
191 }
192 }
193}