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 use inline_c::assert_c;
149
150 #[allow(
151 unexpected_cfgs,
152 reason = "tools like cargo-llvm-coverage pass --cfg coverage"
153 )]
154 #[cfg_attr(coverage_nightly, coverage(off))]
155 #[test]
156 fn test_trap_message_null_terminated() {
157 (assert_c! {
158 #include "tests/wasmer.h"
159
160 int main() {
161 wasm_engine_t* engine = wasm_engine_new();
162 wasm_store_t* store = wasm_store_new(engine);
163
164 wasm_message_t original_message;
165 wasm_name_new_from_string_nt(&original_message, "foobar");
166 assert(original_message.size == 7); wasm_trap_t* trap = wasm_trap_new(store, &original_message);
169 assert(trap);
170
171 wasm_message_t retrieved_message;
172 wasm_trap_message(trap, &retrieved_message);
173 assert(retrieved_message.size == 7);
174
175 wasm_name_delete(&original_message);
176 wasm_name_delete(&retrieved_message);
177 wasm_trap_delete(trap);
178 wasm_store_delete(store);
179 wasm_engine_delete(engine);
180
181 return 0;
182 }
183 })
184 .success();
185 }
186
187 #[allow(
188 unexpected_cfgs,
189 reason = "tools like cargo-llvm-coverage pass --cfg coverage"
190 )]
191 #[cfg_attr(coverage_nightly, coverage(off))]
192 #[test]
193 fn test_trap_message_not_null_terminated() {
194 (assert_c! {
195 #include "tests/wasmer.h"
196
197 int main() {
198 wasm_engine_t* engine = wasm_engine_new();
199 wasm_store_t* store = wasm_store_new(engine);
200
201 wasm_message_t original_message;
202 wasm_name_new_from_string(&original_message, "foobar");
203 assert(original_message.size == 6); wasm_trap_t* trap = wasm_trap_new(store, &original_message);
206 assert(trap);
207
208 wasm_message_t retrieved_message;
209 wasm_trap_message(trap, &retrieved_message);
210 assert(retrieved_message.size == 7);
211
212 wasm_name_delete(&original_message);
213 wasm_name_delete(&retrieved_message);
214 wasm_trap_delete(trap);
215 wasm_store_delete(store);
216 wasm_engine_delete(engine);
217
218 return 0;
219 }
220 })
221 .success();
222 }
223}