wasmer_wasix/syscalls/wasix/
reflect_signature.rs1use crate::{WasiEnv, WasiError, WasiModuleTreeHandles, state::FunctionLookupError};
2use tracing::{instrument, trace};
3use wasmer::{FunctionEnvMut, MemorySize, Type, WasmPtr, WasmSlice};
4use wasmer_wasix_types::wasi::{Bool, Errno, ReflectionResult, WasmValueType};
5
6fn serialize_types(types: &[Type]) -> Result<Vec<WasmValueType>, Errno> {
7 types
8 .iter()
9 .map(|t| {
10 WasmValueType::try_from(*t).map_err(|_| {
11 trace!("Cannot convert type {} to WasmValueType", t);
12 Errno::Inval
13 })
14 })
15 .collect::<Result<Vec<_>, _>>()
16}
17
18#[instrument(
32 level = "trace",
33 skip_all,
34 fields(
35 %function_id,
36 argument_types_ptr = argument_types.offset().into(),
37 argument_types_len,
38 result_types_ptr = result_types.offset().into(),
39 result_types_len,
40 result = result.offset().into()),
41 ret
42)]
43pub fn reflect_signature<M: MemorySize>(
44 mut ctx: FunctionEnvMut<'_, WasiEnv>,
45 function_id: u32,
46 argument_types: WasmPtr<WasmValueType, M>,
47 argument_types_len: u16,
48 result_types: WasmPtr<WasmValueType, M>,
49 result_types_len: u16,
50 result: WasmPtr<ReflectionResult, M>,
51) -> Result<Errno, WasiError> {
52 let is_closure = WasiModuleTreeHandles::is_closure(&mut ctx, function_id).map_err(|e| {
53 trace!("Failed to check if function is a closure: {}", e);
54 WasiError::Exit(Errno::Noexec.into())
55 })?;
56 let cacheable = if is_closure { Bool::False } else { Bool::True };
57
58 let (env, mut store) = ctx.data_and_store_mut();
59
60 let function_lookup_result = env
61 .inner()
62 .indirect_function_table_lookup(&mut store, function_id);
63
64 let memory = unsafe { env.memory_view(&store) };
65 let signature_info = result.deref(&memory);
66
67 let function = match function_lookup_result {
69 Ok(f) => f,
70 Err(e) => {
71 let cacheable = match e {
72 FunctionLookupError::Empty(_) => cacheable,
73 FunctionLookupError::OutOfBounds(_) => Bool::False,
74 _ => Bool::True,
75 };
76 trace!(
77 "Failed to look up function in indirect function table: {}",
78 e
79 );
80 wasi_try_mem_ok!(signature_info.write(ReflectionResult {
81 cacheable,
82 arguments: 0,
83 results: 0,
84 }));
85 return Ok(e.into());
86 }
87 };
88
89 let function_type = function.ty(&store);
90 let arguments = function_type.params();
91 let results = function_type.results();
92
93 wasi_try_mem_ok!(signature_info.write(ReflectionResult {
94 cacheable,
95 arguments: arguments.len() as u16,
96 results: results.len() as u16,
97 }));
98
99 if (arguments.len() as u16 > argument_types_len) {
100 trace!(
101 "Provided arguments buffer is too small {}/{}",
102 argument_types_len,
103 arguments.len()
104 );
105 return Ok(Errno::Overflow);
106 }
107 if (results.len() as u16 > result_types_len) {
108 trace!(
109 "Provided results buffer is too small {}/{}",
110 result_types_len,
111 results.len()
112 );
113 return Ok(Errno::Overflow);
114 }
115
116 let serialized_argument_types = wasi_try_ok!(serialize_types(function_type.params()));
117 let serialized_result_types = wasi_try_ok!(serialize_types(function_type.results()));
118
119 let mut argument_types_slice = wasi_try_mem_ok!(WasmSlice::<WasmValueType>::new(
120 &memory,
121 argument_types.offset().into(),
122 arguments.len() as u64
123 ));
124 let mut result_types_slice = wasi_try_mem_ok!(WasmSlice::<WasmValueType>::new(
125 &memory,
126 result_types.offset().into(),
127 results.len() as u64
128 ));
129
130 wasi_try_mem_ok!(argument_types_slice.write_slice(&serialized_argument_types));
131 wasi_try_mem_ok!(result_types_slice.write_slice(&serialized_result_types));
132
133 Ok(Errno::Success)
134}