wasmer_c_api/wasm_c_api/
trap.rs1use super::store::wasm_store_t;
2use super::types::{wasm_byte_vec_t, wasm_message_t};
3use super::types::{wasm_frame_t, wasm_frame_vec_t};
4use std::ffi::CString;
5use wasmer_api::RuntimeError;
6
7#[allow(non_camel_case_types)]
9pub struct wasm_trap_t {
10 pub(crate) inner: RuntimeError,
11}
12
13impl From<RuntimeError> for wasm_trap_t {
14 fn from(other: RuntimeError) -> Self {
15 Self { inner: other }
16 }
17}
18
19#[unsafe(no_mangle)]
28pub unsafe extern "C" fn wasm_trap_new(
29 _store: &mut wasm_store_t,
30 message: &wasm_message_t,
31) -> Option<Box<wasm_trap_t>> {
32 let message_bytes = message.as_slice();
33
34 let runtime_error = match CString::new(message_bytes) {
40 Ok(cstring) => RuntimeError::new(cstring.into_string().ok()?),
42
43 Err(nul_error) if nul_error.nul_position() + 1 == message_bytes.len() => {
46 let mut vec = nul_error.into_vec();
47 vec.pop();
48
49 RuntimeError::new(String::from_utf8(vec).ok()?)
50 }
51
52 Err(_) => return None,
54 };
55
56 let trap = runtime_error.into();
57
58 Some(Box::new(trap))
59}
60
61#[unsafe(no_mangle)]
67pub unsafe extern "C" fn wasm_trap_delete(_trap: Option<Box<wasm_trap_t>>) {}
68
69#[unsafe(no_mangle)]
112pub unsafe extern "C" fn wasm_trap_message(
113 trap: &wasm_trap_t,
114 out: &mut wasm_byte_vec_t,
116) {
117 let message = trap.inner.message();
118 let mut byte_vec = message.into_bytes();
119 byte_vec.push(0);
120
121 out.set_buffer(byte_vec);
122}
123
124#[unsafe(no_mangle)]
126pub unsafe extern "C" fn wasm_trap_origin(trap: &wasm_trap_t) -> Option<Box<wasm_frame_t>> {
127 trap.inner.trace().first().map(Into::into).map(Box::new)
128}
129
130#[unsafe(no_mangle)]
132pub unsafe extern "C" fn wasm_trap_trace(
133 trap: &wasm_trap_t,
134 out: &mut wasm_frame_vec_t,
136) {
137 let frames = trap.inner.trace();
138 out.set_buffer(
139 frames
140 .iter()
141 .map(|frame| Some(Box::new(frame.into())))
142 .collect(),
143 );
144}
145
146#[cfg(test)]
147mod tests {
148 #[cfg(not(target_os = "windows"))]
149 use inline_c::assert_c;
150 #[cfg(target_os = "windows")]
151 use wasmer_inline_c::assert_c;
152
153 #[allow(
154 unexpected_cfgs,
155 reason = "tools like cargo-llvm-coverage pass --cfg coverage"
156 )]
157 #[cfg_attr(coverage, ignore)]
158 #[test]
159 fn test_trap_message_null_terminated() {
160 (assert_c! {
161 #include "tests/wasmer.h"
162
163 int main() {
164 wasm_engine_t* engine = wasm_engine_new();
165 wasm_store_t* store = wasm_store_new(engine);
166
167 wasm_message_t original_message;
168 wasm_name_new_from_string_nt(&original_message, "foobar");
169 assert(original_message.size == 7); wasm_trap_t* trap = wasm_trap_new(store, &original_message);
172 assert(trap);
173
174 wasm_message_t retrieved_message;
175 wasm_trap_message(trap, &retrieved_message);
176 assert(retrieved_message.size == 7);
177
178 wasm_name_delete(&original_message);
179 wasm_name_delete(&retrieved_message);
180 wasm_trap_delete(trap);
181 wasm_store_delete(store);
182 wasm_engine_delete(engine);
183
184 return 0;
185 }
186 })
187 .success();
188 }
189
190 #[allow(
191 unexpected_cfgs,
192 reason = "tools like cargo-llvm-coverage pass --cfg coverage"
193 )]
194 #[cfg_attr(coverage, ignore)]
195 #[test]
196 fn test_trap_message_not_null_terminated() {
197 (assert_c! {
198 #include "tests/wasmer.h"
199
200 int main() {
201 wasm_engine_t* engine = wasm_engine_new();
202 wasm_store_t* store = wasm_store_new(engine);
203
204 wasm_message_t original_message;
205 wasm_name_new_from_string(&original_message, "foobar");
206 assert(original_message.size == 6); wasm_trap_t* trap = wasm_trap_new(store, &original_message);
209 assert(trap);
210
211 wasm_message_t retrieved_message;
212 wasm_trap_message(trap, &retrieved_message);
213 assert(retrieved_message.size == 7);
214
215 wasm_name_delete(&original_message);
216 wasm_name_delete(&retrieved_message);
217 wasm_trap_delete(trap);
218 wasm_store_delete(store);
219 wasm_engine_delete(engine);
220
221 return 0;
222 }
223 })
224 .success();
225 }
226}