xref: /qemu/rust/qemu-api/src/error.rs (revision 96215036f47403438c7c7869b7cd419bd7a11f82)
1b4ff3cf3SPaolo Bonzini // SPDX-License-Identifier: GPL-2.0-or-later
2b4ff3cf3SPaolo Bonzini 
3b4ff3cf3SPaolo Bonzini //! Error propagation for QEMU Rust code
4b4ff3cf3SPaolo Bonzini //!
5b4ff3cf3SPaolo Bonzini //! This module contains [`Error`], the bridge between Rust errors and
6b4ff3cf3SPaolo Bonzini //! [`Result`](std::result::Result)s and QEMU's C [`Error`](bindings::Error)
7b4ff3cf3SPaolo Bonzini //! struct.
8b4ff3cf3SPaolo Bonzini //!
9b4ff3cf3SPaolo Bonzini //! For FFI code, [`Error`] provides functions to simplify conversion between
10b4ff3cf3SPaolo Bonzini //! the Rust ([`Result<>`](std::result::Result)) and C (`Error**`) conventions:
11b4ff3cf3SPaolo Bonzini //!
12b4ff3cf3SPaolo Bonzini //! * [`ok_or_propagate`](crate::Error::ok_or_propagate),
13b4ff3cf3SPaolo Bonzini //!   [`bool_or_propagate`](crate::Error::bool_or_propagate),
14b4ff3cf3SPaolo Bonzini //!   [`ptr_or_propagate`](crate::Error::ptr_or_propagate) can be used to build
15b4ff3cf3SPaolo Bonzini //!   a C return value while also propagating an error condition
16b4ff3cf3SPaolo Bonzini //!
17b4ff3cf3SPaolo Bonzini //! * [`err_or_else`](crate::Error::err_or_else) and
18b4ff3cf3SPaolo Bonzini //!   [`err_or_unit`](crate::Error::err_or_unit) can be used to build a `Result`
19b4ff3cf3SPaolo Bonzini //!
20b4ff3cf3SPaolo Bonzini //! This module is most commonly used at the boundary between C and Rust code;
21b4ff3cf3SPaolo Bonzini //! other code will usually access it through the
22b4ff3cf3SPaolo Bonzini //! [`qemu_api::Result`](crate::Result) type alias, and will use the
23b4ff3cf3SPaolo Bonzini //! [`std::error::Error`] interface to let C errors participate in Rust's error
24b4ff3cf3SPaolo Bonzini //! handling functionality.
25b4ff3cf3SPaolo Bonzini //!
26b4ff3cf3SPaolo Bonzini //! Rust code can also create use this module to create an error object that
27b4ff3cf3SPaolo Bonzini //! will be passed up to C code, though in most cases this will be done
28b4ff3cf3SPaolo Bonzini //! transparently through the `?` operator.  Errors can be constructed from a
29b4ff3cf3SPaolo Bonzini //! simple error string, from an [`anyhow::Error`] to pass any other Rust error
30b4ff3cf3SPaolo Bonzini //! type up to C code, or from a combination of the two.
31b4ff3cf3SPaolo Bonzini //!
32b4ff3cf3SPaolo Bonzini //! The third case, corresponding to [`Error::with_error`], is the only one that
33b4ff3cf3SPaolo Bonzini //! requires mentioning [`qemu_api::Error`](crate::Error) explicitly.  Similar
34b4ff3cf3SPaolo Bonzini //! to how QEMU's C code handles errno values, the string and the
35b4ff3cf3SPaolo Bonzini //! `anyhow::Error` object will be concatenated with `:` as the separator.
36b4ff3cf3SPaolo Bonzini 
37b4ff3cf3SPaolo Bonzini use std::{
38b4ff3cf3SPaolo Bonzini     borrow::Cow,
39b4ff3cf3SPaolo Bonzini     ffi::{c_char, c_int, c_void, CStr},
40b4ff3cf3SPaolo Bonzini     fmt::{self, Display},
41b4ff3cf3SPaolo Bonzini     panic, ptr,
42b4ff3cf3SPaolo Bonzini };
43b4ff3cf3SPaolo Bonzini 
44b4ff3cf3SPaolo Bonzini use foreign::{prelude::*, OwnedPointer};
45b4ff3cf3SPaolo Bonzini 
46b4ff3cf3SPaolo Bonzini use crate::bindings;
47b4ff3cf3SPaolo Bonzini 
48b4ff3cf3SPaolo Bonzini pub type Result<T> = std::result::Result<T, Error>;
49b4ff3cf3SPaolo Bonzini 
50b4ff3cf3SPaolo Bonzini #[derive(Debug)]
51b4ff3cf3SPaolo Bonzini pub struct Error {
52b4ff3cf3SPaolo Bonzini     msg: Option<Cow<'static, str>>,
53b4ff3cf3SPaolo Bonzini     /// Appends the print string of the error to the msg if not None
54b4ff3cf3SPaolo Bonzini     cause: Option<anyhow::Error>,
55b4ff3cf3SPaolo Bonzini     file: &'static str,
56b4ff3cf3SPaolo Bonzini     line: u32,
57b4ff3cf3SPaolo Bonzini }
58b4ff3cf3SPaolo Bonzini 
59b4ff3cf3SPaolo Bonzini impl std::error::Error for Error {
source(&self) -> Option<&(dyn std::error::Error + 'static)>60b4ff3cf3SPaolo Bonzini     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
61b4ff3cf3SPaolo Bonzini         self.cause.as_ref().map(AsRef::as_ref)
62b4ff3cf3SPaolo Bonzini     }
63b4ff3cf3SPaolo Bonzini 
64b4ff3cf3SPaolo Bonzini     #[allow(deprecated)]
description(&self) -> &str65b4ff3cf3SPaolo Bonzini     fn description(&self) -> &str {
66b4ff3cf3SPaolo Bonzini         self.msg
67b4ff3cf3SPaolo Bonzini             .as_deref()
68b4ff3cf3SPaolo Bonzini             .or_else(|| self.cause.as_deref().map(std::error::Error::description))
69b4ff3cf3SPaolo Bonzini             .expect("no message nor cause?")
70b4ff3cf3SPaolo Bonzini     }
71b4ff3cf3SPaolo Bonzini }
72b4ff3cf3SPaolo Bonzini 
73b4ff3cf3SPaolo Bonzini impl Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result74b4ff3cf3SPaolo Bonzini     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75b4ff3cf3SPaolo Bonzini         let mut prefix = "";
76b4ff3cf3SPaolo Bonzini         if let Some(ref msg) = self.msg {
77b4ff3cf3SPaolo Bonzini             write!(f, "{msg}")?;
78b4ff3cf3SPaolo Bonzini             prefix = ": ";
79b4ff3cf3SPaolo Bonzini         }
80b4ff3cf3SPaolo Bonzini         if let Some(ref cause) = self.cause {
81b4ff3cf3SPaolo Bonzini             write!(f, "{prefix}{cause}")?;
82b4ff3cf3SPaolo Bonzini         } else if prefix.is_empty() {
83b4ff3cf3SPaolo Bonzini             panic!("no message nor cause?");
84b4ff3cf3SPaolo Bonzini         }
85b4ff3cf3SPaolo Bonzini         Ok(())
86b4ff3cf3SPaolo Bonzini     }
87b4ff3cf3SPaolo Bonzini }
88b4ff3cf3SPaolo Bonzini 
89b4ff3cf3SPaolo Bonzini impl From<String> for Error {
90b4ff3cf3SPaolo Bonzini     #[track_caller]
from(msg: String) -> Self91b4ff3cf3SPaolo Bonzini     fn from(msg: String) -> Self {
92b4ff3cf3SPaolo Bonzini         let location = panic::Location::caller();
93b4ff3cf3SPaolo Bonzini         Error {
94b4ff3cf3SPaolo Bonzini             msg: Some(Cow::Owned(msg)),
95b4ff3cf3SPaolo Bonzini             cause: None,
96b4ff3cf3SPaolo Bonzini             file: location.file(),
97b4ff3cf3SPaolo Bonzini             line: location.line(),
98b4ff3cf3SPaolo Bonzini         }
99b4ff3cf3SPaolo Bonzini     }
100b4ff3cf3SPaolo Bonzini }
101b4ff3cf3SPaolo Bonzini 
102b4ff3cf3SPaolo Bonzini impl From<&'static str> for Error {
103b4ff3cf3SPaolo Bonzini     #[track_caller]
from(msg: &'static str) -> Self104b4ff3cf3SPaolo Bonzini     fn from(msg: &'static str) -> Self {
105b4ff3cf3SPaolo Bonzini         let location = panic::Location::caller();
106b4ff3cf3SPaolo Bonzini         Error {
107b4ff3cf3SPaolo Bonzini             msg: Some(Cow::Borrowed(msg)),
108b4ff3cf3SPaolo Bonzini             cause: None,
109b4ff3cf3SPaolo Bonzini             file: location.file(),
110b4ff3cf3SPaolo Bonzini             line: location.line(),
111b4ff3cf3SPaolo Bonzini         }
112b4ff3cf3SPaolo Bonzini     }
113b4ff3cf3SPaolo Bonzini }
114b4ff3cf3SPaolo Bonzini 
115b4ff3cf3SPaolo Bonzini impl From<anyhow::Error> for Error {
116b4ff3cf3SPaolo Bonzini     #[track_caller]
from(error: anyhow::Error) -> Self117b4ff3cf3SPaolo Bonzini     fn from(error: anyhow::Error) -> Self {
118b4ff3cf3SPaolo Bonzini         let location = panic::Location::caller();
119b4ff3cf3SPaolo Bonzini         Error {
120b4ff3cf3SPaolo Bonzini             msg: None,
121b4ff3cf3SPaolo Bonzini             cause: Some(error),
122b4ff3cf3SPaolo Bonzini             file: location.file(),
123b4ff3cf3SPaolo Bonzini             line: location.line(),
124b4ff3cf3SPaolo Bonzini         }
125b4ff3cf3SPaolo Bonzini     }
126b4ff3cf3SPaolo Bonzini }
127b4ff3cf3SPaolo Bonzini 
128b4ff3cf3SPaolo Bonzini impl Error {
129b4ff3cf3SPaolo Bonzini     /// Create a new error, prepending `msg` to the
130b4ff3cf3SPaolo Bonzini     /// description of `cause`
131b4ff3cf3SPaolo Bonzini     #[track_caller]
with_error(msg: impl Into<Cow<'static, str>>, cause: impl Into<anyhow::Error>) -> Self132b4ff3cf3SPaolo Bonzini     pub fn with_error(msg: impl Into<Cow<'static, str>>, cause: impl Into<anyhow::Error>) -> Self {
133b4ff3cf3SPaolo Bonzini         let location = panic::Location::caller();
134b4ff3cf3SPaolo Bonzini         Error {
135b4ff3cf3SPaolo Bonzini             msg: Some(msg.into()),
136b4ff3cf3SPaolo Bonzini             cause: Some(cause.into()),
137b4ff3cf3SPaolo Bonzini             file: location.file(),
138b4ff3cf3SPaolo Bonzini             line: location.line(),
139b4ff3cf3SPaolo Bonzini         }
140b4ff3cf3SPaolo Bonzini     }
141b4ff3cf3SPaolo Bonzini 
142b4ff3cf3SPaolo Bonzini     /// Consume a result, returning `false` if it is an error and
143b4ff3cf3SPaolo Bonzini     /// `true` if it is successful.  The error is propagated into
144b4ff3cf3SPaolo Bonzini     /// `errp` like the C API `error_propagate` would do.
145b4ff3cf3SPaolo Bonzini     ///
146b4ff3cf3SPaolo Bonzini     /// # Safety
147b4ff3cf3SPaolo Bonzini     ///
148b4ff3cf3SPaolo Bonzini     /// `errp` must be a valid argument to `error_propagate`;
149b4ff3cf3SPaolo Bonzini     /// typically it is received from C code and need not be
150b4ff3cf3SPaolo Bonzini     /// checked further at the Rust↔C boundary.
bool_or_propagate(result: Result<()>, errp: *mut *mut bindings::Error) -> bool151b4ff3cf3SPaolo Bonzini     pub unsafe fn bool_or_propagate(result: Result<()>, errp: *mut *mut bindings::Error) -> bool {
152b4ff3cf3SPaolo Bonzini         // SAFETY: caller guarantees errp is valid
153b4ff3cf3SPaolo Bonzini         unsafe { Self::ok_or_propagate(result, errp) }.is_some()
154b4ff3cf3SPaolo Bonzini     }
155b4ff3cf3SPaolo Bonzini 
156b4ff3cf3SPaolo Bonzini     /// Consume a result, returning a `NULL` pointer if it is an error and
157b4ff3cf3SPaolo Bonzini     /// a C representation of the contents if it is successful.  This is
158b4ff3cf3SPaolo Bonzini     /// similar to the C API `error_propagate`, but it panics if `*errp`
159b4ff3cf3SPaolo Bonzini     /// is not `NULL`.
160b4ff3cf3SPaolo Bonzini     ///
161b4ff3cf3SPaolo Bonzini     /// # Safety
162b4ff3cf3SPaolo Bonzini     ///
163b4ff3cf3SPaolo Bonzini     /// `errp` must be a valid argument to `error_propagate`;
164b4ff3cf3SPaolo Bonzini     /// typically it is received from C code and need not be
165b4ff3cf3SPaolo Bonzini     /// checked further at the Rust↔C boundary.
166b4ff3cf3SPaolo Bonzini     ///
167b4ff3cf3SPaolo Bonzini     /// See [`propagate`](Error::propagate) for more information.
168b4ff3cf3SPaolo Bonzini     #[must_use]
ptr_or_propagate<T: CloneToForeign>( result: Result<T>, errp: *mut *mut bindings::Error, ) -> *mut T::Foreign169b4ff3cf3SPaolo Bonzini     pub unsafe fn ptr_or_propagate<T: CloneToForeign>(
170b4ff3cf3SPaolo Bonzini         result: Result<T>,
171b4ff3cf3SPaolo Bonzini         errp: *mut *mut bindings::Error,
172b4ff3cf3SPaolo Bonzini     ) -> *mut T::Foreign {
173b4ff3cf3SPaolo Bonzini         // SAFETY: caller guarantees errp is valid
174b4ff3cf3SPaolo Bonzini         unsafe { Self::ok_or_propagate(result, errp) }.clone_to_foreign_ptr()
175b4ff3cf3SPaolo Bonzini     }
176b4ff3cf3SPaolo Bonzini 
177b4ff3cf3SPaolo Bonzini     /// Consume a result in the same way as `self.ok()`, but also propagate
178b4ff3cf3SPaolo Bonzini     /// a possible error into `errp`.  This is similar to the C API
179b4ff3cf3SPaolo Bonzini     /// `error_propagate`, but it panics if `*errp` is not `NULL`.
180b4ff3cf3SPaolo Bonzini     ///
181b4ff3cf3SPaolo Bonzini     /// # Safety
182b4ff3cf3SPaolo Bonzini     ///
183b4ff3cf3SPaolo Bonzini     /// `errp` must be a valid argument to `error_propagate`;
184b4ff3cf3SPaolo Bonzini     /// typically it is received from C code and need not be
185b4ff3cf3SPaolo Bonzini     /// checked further at the Rust↔C boundary.
186b4ff3cf3SPaolo Bonzini     ///
187b4ff3cf3SPaolo Bonzini     /// See [`propagate`](Error::propagate) for more information.
ok_or_propagate<T>( result: Result<T>, errp: *mut *mut bindings::Error, ) -> Option<T>188b4ff3cf3SPaolo Bonzini     pub unsafe fn ok_or_propagate<T>(
189b4ff3cf3SPaolo Bonzini         result: Result<T>,
190b4ff3cf3SPaolo Bonzini         errp: *mut *mut bindings::Error,
191b4ff3cf3SPaolo Bonzini     ) -> Option<T> {
192b4ff3cf3SPaolo Bonzini         result.map_err(|err| unsafe { err.propagate(errp) }).ok()
193b4ff3cf3SPaolo Bonzini     }
194b4ff3cf3SPaolo Bonzini 
195b4ff3cf3SPaolo Bonzini     /// Equivalent of the C function `error_propagate`.  Fill `*errp`
196b4ff3cf3SPaolo Bonzini     /// with the information container in `self` if `errp` is not NULL;
197b4ff3cf3SPaolo Bonzini     /// then consume it.
198b4ff3cf3SPaolo Bonzini     ///
199b4ff3cf3SPaolo Bonzini     /// This is similar to the C API `error_propagate`, but it panics if
200b4ff3cf3SPaolo Bonzini     /// `*errp` is not `NULL`.
201b4ff3cf3SPaolo Bonzini     ///
202b4ff3cf3SPaolo Bonzini     /// # Safety
203b4ff3cf3SPaolo Bonzini     ///
204b4ff3cf3SPaolo Bonzini     /// `errp` must be a valid argument to `error_propagate`; it can be
205b4ff3cf3SPaolo Bonzini     /// `NULL` or it can point to any of:
206b4ff3cf3SPaolo Bonzini     /// * `error_abort`
207b4ff3cf3SPaolo Bonzini     /// * `error_fatal`
208b4ff3cf3SPaolo Bonzini     /// * a local variable of (C) type `Error *`
209b4ff3cf3SPaolo Bonzini     ///
210b4ff3cf3SPaolo Bonzini     /// Typically `errp` is received from C code and need not be
211b4ff3cf3SPaolo Bonzini     /// checked further at the Rust↔C boundary.
propagate(self, errp: *mut *mut bindings::Error)212b4ff3cf3SPaolo Bonzini     pub unsafe fn propagate(self, errp: *mut *mut bindings::Error) {
213b4ff3cf3SPaolo Bonzini         if errp.is_null() {
214b4ff3cf3SPaolo Bonzini             return;
215b4ff3cf3SPaolo Bonzini         }
216b4ff3cf3SPaolo Bonzini 
217b4ff3cf3SPaolo Bonzini         // SAFETY: caller guarantees that errp and *errp are valid
218b4ff3cf3SPaolo Bonzini         unsafe {
219b4ff3cf3SPaolo Bonzini             assert_eq!(*errp, ptr::null_mut());
220b4ff3cf3SPaolo Bonzini             bindings::error_propagate(errp, self.clone_to_foreign_ptr());
221b4ff3cf3SPaolo Bonzini         }
222b4ff3cf3SPaolo Bonzini     }
223b4ff3cf3SPaolo Bonzini 
224b4ff3cf3SPaolo Bonzini     /// Convert a C `Error*` into a Rust `Result`, using
225b4ff3cf3SPaolo Bonzini     /// `Ok(())` if `c_error` is NULL.  Free the `Error*`.
226b4ff3cf3SPaolo Bonzini     ///
227b4ff3cf3SPaolo Bonzini     /// # Safety
228b4ff3cf3SPaolo Bonzini     ///
229b4ff3cf3SPaolo Bonzini     /// `c_error` must be `NULL` or valid; typically it was initialized
230b4ff3cf3SPaolo Bonzini     /// with `ptr::null_mut()` and passed by reference to a C function.
err_or_unit(c_error: *mut bindings::Error) -> Result<()>231b4ff3cf3SPaolo Bonzini     pub unsafe fn err_or_unit(c_error: *mut bindings::Error) -> Result<()> {
232b4ff3cf3SPaolo Bonzini         // SAFETY: caller guarantees c_error is valid
233b4ff3cf3SPaolo Bonzini         unsafe { Self::err_or_else(c_error, || ()) }
234b4ff3cf3SPaolo Bonzini     }
235b4ff3cf3SPaolo Bonzini 
236b4ff3cf3SPaolo Bonzini     /// Convert a C `Error*` into a Rust `Result`, calling `f()` to
237b4ff3cf3SPaolo Bonzini     /// obtain an `Ok` value if `c_error` is NULL.  Free the `Error*`.
238b4ff3cf3SPaolo Bonzini     ///
239b4ff3cf3SPaolo Bonzini     /// # Safety
240b4ff3cf3SPaolo Bonzini     ///
241b4ff3cf3SPaolo Bonzini     /// `c_error` must be `NULL` or point to a valid C [`struct
242b4ff3cf3SPaolo Bonzini     /// Error`](bindings::Error); typically it was initialized with
243b4ff3cf3SPaolo Bonzini     /// `ptr::null_mut()` and passed by reference to a C function.
err_or_else<T, F: FnOnce() -> T>( c_error: *mut bindings::Error, f: F, ) -> Result<T>244b4ff3cf3SPaolo Bonzini     pub unsafe fn err_or_else<T, F: FnOnce() -> T>(
245b4ff3cf3SPaolo Bonzini         c_error: *mut bindings::Error,
246b4ff3cf3SPaolo Bonzini         f: F,
247b4ff3cf3SPaolo Bonzini     ) -> Result<T> {
248b4ff3cf3SPaolo Bonzini         // SAFETY: caller guarantees c_error is valid
249b4ff3cf3SPaolo Bonzini         let err = unsafe { Option::<Self>::from_foreign(c_error) };
250b4ff3cf3SPaolo Bonzini         match err {
251b4ff3cf3SPaolo Bonzini             None => Ok(f()),
252b4ff3cf3SPaolo Bonzini             Some(err) => Err(err),
253b4ff3cf3SPaolo Bonzini         }
254b4ff3cf3SPaolo Bonzini     }
255b4ff3cf3SPaolo Bonzini }
256b4ff3cf3SPaolo Bonzini 
257b4ff3cf3SPaolo Bonzini impl FreeForeign for Error {
258b4ff3cf3SPaolo Bonzini     type Foreign = bindings::Error;
259b4ff3cf3SPaolo Bonzini 
free_foreign(p: *mut bindings::Error)260b4ff3cf3SPaolo Bonzini     unsafe fn free_foreign(p: *mut bindings::Error) {
261b4ff3cf3SPaolo Bonzini         // SAFETY: caller guarantees p is valid
262b4ff3cf3SPaolo Bonzini         unsafe {
263b4ff3cf3SPaolo Bonzini             bindings::error_free(p);
264b4ff3cf3SPaolo Bonzini         }
265b4ff3cf3SPaolo Bonzini     }
266b4ff3cf3SPaolo Bonzini }
267b4ff3cf3SPaolo Bonzini 
268b4ff3cf3SPaolo Bonzini impl CloneToForeign for Error {
clone_to_foreign(&self) -> OwnedPointer<Self>269b4ff3cf3SPaolo Bonzini     fn clone_to_foreign(&self) -> OwnedPointer<Self> {
270b4ff3cf3SPaolo Bonzini         // SAFETY: all arguments are controlled by this function
271b4ff3cf3SPaolo Bonzini         unsafe {
272b4ff3cf3SPaolo Bonzini             let err: *mut c_void = libc::malloc(std::mem::size_of::<bindings::Error>());
273b4ff3cf3SPaolo Bonzini             let err: &mut bindings::Error = &mut *err.cast();
274b4ff3cf3SPaolo Bonzini             *err = bindings::Error {
275b4ff3cf3SPaolo Bonzini                 msg: format!("{self}").clone_to_foreign_ptr(),
276b4ff3cf3SPaolo Bonzini                 err_class: bindings::ERROR_CLASS_GENERIC_ERROR,
277b4ff3cf3SPaolo Bonzini                 src_len: self.file.len() as c_int,
278b4ff3cf3SPaolo Bonzini                 src: self.file.as_ptr().cast::<c_char>(),
279b4ff3cf3SPaolo Bonzini                 line: self.line as c_int,
280b4ff3cf3SPaolo Bonzini                 func: ptr::null_mut(),
281b4ff3cf3SPaolo Bonzini                 hint: ptr::null_mut(),
282b4ff3cf3SPaolo Bonzini             };
283b4ff3cf3SPaolo Bonzini             OwnedPointer::new(err)
284b4ff3cf3SPaolo Bonzini         }
285b4ff3cf3SPaolo Bonzini     }
286b4ff3cf3SPaolo Bonzini }
287b4ff3cf3SPaolo Bonzini 
288b4ff3cf3SPaolo Bonzini impl FromForeign for Error {
cloned_from_foreign(c_error: *const bindings::Error) -> Self289b4ff3cf3SPaolo Bonzini     unsafe fn cloned_from_foreign(c_error: *const bindings::Error) -> Self {
290b4ff3cf3SPaolo Bonzini         // SAFETY: caller guarantees c_error is valid
291b4ff3cf3SPaolo Bonzini         unsafe {
292b4ff3cf3SPaolo Bonzini             let error = &*c_error;
293b4ff3cf3SPaolo Bonzini             let file = if error.src_len < 0 {
294b4ff3cf3SPaolo Bonzini                 // NUL-terminated
295b4ff3cf3SPaolo Bonzini                 CStr::from_ptr(error.src).to_str()
296b4ff3cf3SPaolo Bonzini             } else {
297b4ff3cf3SPaolo Bonzini                 // Can become str::from_utf8 with Rust 1.87.0
298b4ff3cf3SPaolo Bonzini                 std::str::from_utf8(std::slice::from_raw_parts(
299b4ff3cf3SPaolo Bonzini                     &*error.src.cast::<u8>(),
300b4ff3cf3SPaolo Bonzini                     error.src_len as usize,
301b4ff3cf3SPaolo Bonzini                 ))
302b4ff3cf3SPaolo Bonzini             };
303b4ff3cf3SPaolo Bonzini 
304b4ff3cf3SPaolo Bonzini             Error {
305b4ff3cf3SPaolo Bonzini                 msg: FromForeign::cloned_from_foreign(error.msg),
306b4ff3cf3SPaolo Bonzini                 cause: None,
307b4ff3cf3SPaolo Bonzini                 file: file.unwrap(),
308b4ff3cf3SPaolo Bonzini                 line: error.line as u32,
309b4ff3cf3SPaolo Bonzini             }
310b4ff3cf3SPaolo Bonzini         }
311b4ff3cf3SPaolo Bonzini     }
312b4ff3cf3SPaolo Bonzini }
313*9a33f49fSPaolo Bonzini 
314*9a33f49fSPaolo Bonzini #[cfg(test)]
315*9a33f49fSPaolo Bonzini mod tests {
316*9a33f49fSPaolo Bonzini     use std::ffi::CStr;
317*9a33f49fSPaolo Bonzini 
318*9a33f49fSPaolo Bonzini     use anyhow::anyhow;
319*9a33f49fSPaolo Bonzini     use foreign::OwnedPointer;
320*9a33f49fSPaolo Bonzini 
321*9a33f49fSPaolo Bonzini     use super::*;
322*9a33f49fSPaolo Bonzini     use crate::{assert_match, bindings};
323*9a33f49fSPaolo Bonzini 
324*9a33f49fSPaolo Bonzini     #[track_caller]
error_for_test(msg: &CStr) -> OwnedPointer<Error>325*9a33f49fSPaolo Bonzini     fn error_for_test(msg: &CStr) -> OwnedPointer<Error> {
326*9a33f49fSPaolo Bonzini         // SAFETY: all arguments are controlled by this function
327*9a33f49fSPaolo Bonzini         let location = panic::Location::caller();
328*9a33f49fSPaolo Bonzini         unsafe {
329*9a33f49fSPaolo Bonzini             let err: *mut c_void = libc::malloc(std::mem::size_of::<bindings::Error>());
330*9a33f49fSPaolo Bonzini             let err: &mut bindings::Error = &mut *err.cast();
331*9a33f49fSPaolo Bonzini             *err = bindings::Error {
332*9a33f49fSPaolo Bonzini                 msg: msg.clone_to_foreign_ptr(),
333*9a33f49fSPaolo Bonzini                 err_class: bindings::ERROR_CLASS_GENERIC_ERROR,
334*9a33f49fSPaolo Bonzini                 src_len: location.file().len() as c_int,
335*9a33f49fSPaolo Bonzini                 src: location.file().as_ptr().cast::<c_char>(),
336*9a33f49fSPaolo Bonzini                 line: location.line() as c_int,
337*9a33f49fSPaolo Bonzini                 func: ptr::null_mut(),
338*9a33f49fSPaolo Bonzini                 hint: ptr::null_mut(),
339*9a33f49fSPaolo Bonzini             };
340*9a33f49fSPaolo Bonzini             OwnedPointer::new(err)
341*9a33f49fSPaolo Bonzini         }
342*9a33f49fSPaolo Bonzini     }
343*9a33f49fSPaolo Bonzini 
error_get_pretty<'a>(local_err: *mut bindings::Error) -> &'a CStr344*9a33f49fSPaolo Bonzini     unsafe fn error_get_pretty<'a>(local_err: *mut bindings::Error) -> &'a CStr {
345*9a33f49fSPaolo Bonzini         unsafe { CStr::from_ptr(bindings::error_get_pretty(local_err)) }
346*9a33f49fSPaolo Bonzini     }
347*9a33f49fSPaolo Bonzini 
348*9a33f49fSPaolo Bonzini     #[test]
349*9a33f49fSPaolo Bonzini     #[allow(deprecated)]
test_description()350*9a33f49fSPaolo Bonzini     fn test_description() {
351*9a33f49fSPaolo Bonzini         use std::error::Error;
352*9a33f49fSPaolo Bonzini 
353*9a33f49fSPaolo Bonzini         assert_eq!(super::Error::from("msg").description(), "msg");
354*9a33f49fSPaolo Bonzini         assert_eq!(super::Error::from("msg".to_owned()).description(), "msg");
355*9a33f49fSPaolo Bonzini     }
356*9a33f49fSPaolo Bonzini 
357*9a33f49fSPaolo Bonzini     #[test]
test_display()358*9a33f49fSPaolo Bonzini     fn test_display() {
359*9a33f49fSPaolo Bonzini         assert_eq!(&*format!("{}", Error::from("msg")), "msg");
360*9a33f49fSPaolo Bonzini         assert_eq!(&*format!("{}", Error::from("msg".to_owned())), "msg");
361*9a33f49fSPaolo Bonzini         assert_eq!(&*format!("{}", Error::from(anyhow!("msg"))), "msg");
362*9a33f49fSPaolo Bonzini 
363*9a33f49fSPaolo Bonzini         assert_eq!(
364*9a33f49fSPaolo Bonzini             &*format!("{}", Error::with_error("msg", anyhow!("cause"))),
365*9a33f49fSPaolo Bonzini             "msg: cause"
366*9a33f49fSPaolo Bonzini         );
367*9a33f49fSPaolo Bonzini     }
368*9a33f49fSPaolo Bonzini 
369*9a33f49fSPaolo Bonzini     #[test]
test_bool_or_propagate()370*9a33f49fSPaolo Bonzini     fn test_bool_or_propagate() {
371*9a33f49fSPaolo Bonzini         unsafe {
372*9a33f49fSPaolo Bonzini             let mut local_err: *mut bindings::Error = ptr::null_mut();
373*9a33f49fSPaolo Bonzini 
374*9a33f49fSPaolo Bonzini             assert!(Error::bool_or_propagate(Ok(()), &mut local_err));
375*9a33f49fSPaolo Bonzini             assert_eq!(local_err, ptr::null_mut());
376*9a33f49fSPaolo Bonzini 
377*9a33f49fSPaolo Bonzini             let my_err = Error::from("msg");
378*9a33f49fSPaolo Bonzini             assert!(!Error::bool_or_propagate(Err(my_err), &mut local_err));
379*9a33f49fSPaolo Bonzini             assert_ne!(local_err, ptr::null_mut());
380*9a33f49fSPaolo Bonzini             assert_eq!(error_get_pretty(local_err), c"msg");
381*9a33f49fSPaolo Bonzini             bindings::error_free(local_err);
382*9a33f49fSPaolo Bonzini         }
383*9a33f49fSPaolo Bonzini     }
384*9a33f49fSPaolo Bonzini 
385*9a33f49fSPaolo Bonzini     #[test]
test_ptr_or_propagate()386*9a33f49fSPaolo Bonzini     fn test_ptr_or_propagate() {
387*9a33f49fSPaolo Bonzini         unsafe {
388*9a33f49fSPaolo Bonzini             let mut local_err: *mut bindings::Error = ptr::null_mut();
389*9a33f49fSPaolo Bonzini 
390*9a33f49fSPaolo Bonzini             let ret = Error::ptr_or_propagate(Ok("abc".to_owned()), &mut local_err);
391*9a33f49fSPaolo Bonzini             assert_eq!(String::from_foreign(ret), "abc");
392*9a33f49fSPaolo Bonzini             assert_eq!(local_err, ptr::null_mut());
393*9a33f49fSPaolo Bonzini 
394*9a33f49fSPaolo Bonzini             let my_err = Error::from("msg");
395*9a33f49fSPaolo Bonzini             assert_eq!(
396*9a33f49fSPaolo Bonzini                 Error::ptr_or_propagate(Err::<String, _>(my_err), &mut local_err),
397*9a33f49fSPaolo Bonzini                 ptr::null_mut()
398*9a33f49fSPaolo Bonzini             );
399*9a33f49fSPaolo Bonzini             assert_ne!(local_err, ptr::null_mut());
400*9a33f49fSPaolo Bonzini             assert_eq!(error_get_pretty(local_err), c"msg");
401*9a33f49fSPaolo Bonzini             bindings::error_free(local_err);
402*9a33f49fSPaolo Bonzini         }
403*9a33f49fSPaolo Bonzini     }
404*9a33f49fSPaolo Bonzini 
405*9a33f49fSPaolo Bonzini     #[test]
test_err_or_unit()406*9a33f49fSPaolo Bonzini     fn test_err_or_unit() {
407*9a33f49fSPaolo Bonzini         unsafe {
408*9a33f49fSPaolo Bonzini             let result = Error::err_or_unit(ptr::null_mut());
409*9a33f49fSPaolo Bonzini             assert_match!(result, Ok(()));
410*9a33f49fSPaolo Bonzini 
411*9a33f49fSPaolo Bonzini             let err = error_for_test(c"msg");
412*9a33f49fSPaolo Bonzini             let err = Error::err_or_unit(err.into_inner()).unwrap_err();
413*9a33f49fSPaolo Bonzini             assert_eq!(&*format!("{err}"), "msg");
414*9a33f49fSPaolo Bonzini         }
415*9a33f49fSPaolo Bonzini     }
416*9a33f49fSPaolo Bonzini }
417