wasmer_wasix/syscalls/wasix/
dlopen.rs1use super::*;
2use crate::{state::DlModuleSpec, syscalls::*};
3
4#[instrument(level = "trace", skip_all, fields(path = field::Empty, ld_library_path = field::Empty, flags), ret)]
6pub fn dlopen<M: MemorySize>(
7 mut ctx: FunctionEnvMut<'_, WasiEnv>,
8 path: WasmPtr<u8, M>,
9 path_len: M::Offset,
10 flags: DlFlags,
11 err_buf: WasmPtr<u8, M>,
12 err_buf_len: M::Offset,
13 ld_library_path: WasmPtr<u8, M>,
14 ld_library_path_len: M::Offset,
15 out_handle: WasmPtr<DlHandle, M>,
16) -> Result<Errno, WasiError> {
17 WasiEnv::do_pending_operations(&mut ctx)?;
18
19 let (env, mut store) = ctx.data_and_store_mut();
20 let memory = unsafe { env.memory_view(&store) };
21
22 let env_inner = unsafe { env.inner() };
23 let Some(linker) = env_inner.linker() else {
24 wasi_dl_err!(
25 "The current instance is not a dynamically-linked instance",
26 memory,
27 err_buf,
28 err_buf_len
29 );
30 };
31
32 if path.is_null() {
33 wasi_try_mem_ok!(out_handle.write(&memory, crate::state::MAIN_MODULE_HANDLE.into()));
35 return Ok(Errno::Success);
36 }
37
38 let path = unsafe { get_input_str_ok!(&memory, path, path_len) };
39 Span::current().record("path", path.as_str());
40
41 let ld_library_path =
42 unsafe { get_input_str_ok!(&memory, ld_library_path, ld_library_path_len) };
43 Span::current().record("ld_library_path", ld_library_path.as_str());
44 let ld_library_path = ld_library_path
45 .split(':')
46 .map(Path::new)
47 .collect::<Vec<_>>();
48
49 let linker = linker.clone();
50
51 let location = DlModuleSpec::FileSystem {
52 module_spec: Path::new(&path),
53 ld_library_path: ld_library_path.as_slice(),
54 };
55 let module_handle = linker.load_module(location, &mut ctx);
56
57 let (env, mut store) = ctx.data_and_store_mut();
59 let memory = unsafe { env.memory_view(&store) };
60
61 let module_handle = wasi_try_dl!(
62 module_handle,
63 "failed to load module: {}",
64 memory,
65 err_buf,
66 err_buf_len
67 );
68
69 wasi_try_mem_ok!(out_handle.write(&memory, module_handle.into()));
70
71 Ok(Errno::Success)
72}
73
74pub(crate) fn write_dl_error<M: MemorySize>(
75 mut err: &str,
76 memory: &MemoryView,
77 err_buf: WasmPtr<u8, M>,
78 err_buf_len: u64,
79) -> Result<(), MemoryAccessError> {
80 let err_buf_len = err_buf_len as usize;
81
82 if err_buf_len == 0 {
85 return Ok(());
86 }
87
88 let max_err_len = err_buf_len - 1;
90 let mut err_len = err.len();
91
92 if err_len > max_err_len {
93 err_len = max_err_len;
94 err = &err[..err_len];
95 }
96
97 let Ok(err_len_offset) = M::Offset::try_from(err_len + 1) else {
98 panic!("Failed to convert size to offset")
99 };
100 let mut err_buf = err_buf.slice(memory, err_len_offset)?.access()?;
101 let dst = err_buf.as_mut();
102 dst[..err_len].copy_from_slice(err.as_bytes());
103 dst[err_len] = 0;
104
105 Ok(())
106}
107
108#[cfg(all(test, not(target_arch = "wasm32")))]
109mod tests {
110 use super::write_dl_error;
111 use wasmer::{Memory, Memory32, MemoryType, Store, WasmPtr};
112
113 #[test]
114 fn write_dl_error_zero_len_buffer_writes_nothing() {
115 let mut store = Store::default();
116 let memory = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap();
117 let view = memory.view(&store);
118
119 let err_buf = WasmPtr::<u8, Memory32>::new(0);
122 let res = write_dl_error::<Memory32>("failed to load module", &view, err_buf, 0);
123 assert!(res.is_ok());
124 assert_eq!(view.read_u8(0).unwrap(), 0);
125 }
126
127 #[test]
128 fn write_dl_error_reserves_room_for_nul() {
129 let mut store = Store::default();
130 let memory = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap();
131 let view = memory.view(&store);
132
133 let msg = "abcd";
136 let err_buf = WasmPtr::<u8, Memory32>::new(0);
137 write_dl_error::<Memory32>(msg, &view, err_buf, msg.len() as u64).unwrap();
138
139 let mut got = [1u8; 5];
140 view.read(0, &mut got).unwrap();
141 assert_eq!(&got[..4], b"abc\0");
142 assert_eq!(got[4], 0);
143 }
144}