wasmer_wasix/syscalls/wasix/
call_dynamic.rs1use super::*;
2use crate::syscalls::*;
3use wasmer::Type;
4use wasmer::ValueType;
5
6macro_rules! write_value {
7 ($memory:expr, $offset:expr, $max:expr, $strict:expr, $value:expr) => {{
8 let bytes = $value.to_le_bytes();
9 if $offset + bytes.len() as u64 <= $max {
10 $memory.write($offset, &bytes)?;
11 $offset += bytes.len() as u64;
12 Ok(true)
13 } else {
14 Ok(!$strict)
15 }
16 }};
17}
18
19fn write_value(
20 memory: &MemoryView,
21 offset: &mut u64,
22 max: u64,
23 strict: bool,
24 value: &Value,
25) -> Result<bool, MemoryAccessError> {
26 match value {
27 Value::I32(value) => write_value!(memory, *offset, max, strict, value),
28 Value::I64(value) => write_value!(memory, *offset, max, strict, value),
29 Value::F32(value) => write_value!(memory, *offset, max, strict, value),
30 Value::F64(value) => write_value!(memory, *offset, max, strict, value),
31 Value::V128(value) => write_value!(memory, *offset, max, strict, value),
32 _ => panic!("Cannot write non-scalar value as bytes"),
34 }
35}
36
37macro_rules! read_value {
38 ($memory:expr, $offset:expr, $max:expr, $strict:expr, $ty:ident, $val:ident, $len:expr) => {{
39 if $offset + $len > $max {
40 Ok(if $strict {
41 None
42 } else {
43 Some(Value::$val($ty::default()))
44 })
45 } else {
46 let mut buffer = [0u8; $len];
47 $memory.read($offset, &mut buffer)?;
48 $offset += $len;
49 Ok(Some(Value::$val($ty::from_le_bytes(buffer))))
50 }
51 }};
52}
53
54fn read_value(
55 memory: &MemoryView,
56 offset: &mut u64,
57 max: u64,
58 strict: bool,
59 ty: &Type,
60) -> Result<Option<Value>, MemoryAccessError> {
61 match ty {
62 Type::I32 => read_value!(memory, *offset, max, strict, i32, I32, 4),
63 Type::I64 => read_value!(memory, *offset, max, strict, i64, I64, 8),
64 Type::F32 => read_value!(memory, *offset, max, strict, f32, F32, 4),
65 Type::F64 => read_value!(memory, *offset, max, strict, f64, F64, 8),
66 Type::V128 => read_value!(memory, *offset, max, strict, u128, V128, 16),
67 _ => panic!("Cannot read non-scalar value from memory"),
69 }
70}
71
72#[instrument(
101 level = "trace",
102 skip_all,
103 fields(%function_id, values_ptr = values.offset().into(), results_ptr = results.offset().into()),
104 ret
105)]
106#[allow(clippy::result_large_err)]
107pub fn call_dynamic<M: MemorySize>(
108 mut ctx: FunctionEnvMut<'_, WasiEnv>,
109 function_id: u32,
110 values: WasmPtr<u8, M>,
111 values_len: M::Offset,
112 results: WasmPtr<u8, M>,
113 results_len: M::Offset,
114 strict: Bool,
115) -> Result<Errno, RuntimeError> {
116 let (env, mut store) = ctx.data_and_store_mut();
117
118 let strict = matches!(strict, Bool::True);
119
120 let function = wasi_try_ok!(
121 env.inner()
122 .indirect_function_table_lookup(&mut store, function_id)
123 .map_err(Errno::from)
124 );
125
126 let function_type = function.ty(&store);
127
128 let memory = unsafe { env.memory_view(&store) };
129 let mut current_values_offset: u64 = values.offset().into();
130 let max_values_offset = current_values_offset + values_len.into();
131 let mut values_buffer = vec![];
132 for ty in function_type.params() {
133 let Some(value) = wasi_try_mem_ok!(read_value(
134 &memory,
135 &mut current_values_offset,
136 max_values_offset,
137 strict,
138 ty
139 )) else {
140 return Ok(Errno::Inval);
141 };
142 values_buffer.push(value);
143 }
144
145 if strict && current_values_offset != max_values_offset {
146 return Ok(Errno::Inval);
148 }
149
150 let result_values = function
151 .call(&mut store, values_buffer.as_slice())
152 .map_err(crate::flatten_runtime_error)?;
153
154 let memory = unsafe { env.memory_view(&store) };
155 let mut current_results_offset: u64 = results.offset().into();
156 let max_results_offset = current_results_offset + results_len.into();
157 for result_value in result_values {
158 wasi_try_mem_ok!(write_value(
159 &memory,
160 &mut current_results_offset,
161 max_results_offset,
162 strict,
163 &result_value
164 ));
165 }
166
167 if strict && current_results_offset != max_results_offset {
168 return Ok(Errno::Inval);
170 }
171
172 Ok(Errno::Success)
173}