xref: /openbmc/qemu/rust/util/src/error.rs (revision 917ac07f9aef579b9538a81d45f45850aba42906)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 //! Error propagation for QEMU Rust code
4 //!
5 //! This module contains [`Error`], the bridge between Rust errors and
6 //! [`Result`](std::result::Result)s and QEMU's C [`Error`](bindings::Error)
7 //! struct.
8 //!
9 //! For FFI code, [`Error`] provides functions to simplify conversion between
10 //! the Rust ([`Result<>`](std::result::Result)) and C (`Error**`) conventions:
11 //!
12 //! * [`ok_or_propagate`](crate::Error::ok_or_propagate),
13 //!   [`bool_or_propagate`](crate::Error::bool_or_propagate),
14 //!   [`ptr_or_propagate`](crate::Error::ptr_or_propagate) can be used to build
15 //!   a C return value while also propagating an error condition
16 //!
17 //! * [`with_errp`](crate::Error::with_errp) can be used to build a `Result`
18 //!
19 //! This module is most commonly used at the boundary between C and Rust code;
20 //! other code will usually access it through the
21 //! [`utils::Result`](crate::Result) type alias, and will use the
22 //! [`std::error::Error`] interface to let C errors participate in Rust's error
23 //! handling functionality.
24 //!
25 //! Rust code can also create use this module to create an error object that
26 //! will be passed up to C code, though in most cases this will be done
27 //! transparently through the `?` operator.  Errors can be constructed from a
28 //! simple error string, from an [`anyhow::Error`] to pass any other Rust error
29 //! type up to C code, or from a combination of the two.
30 //!
31 //! The third case, corresponding to [`Error::with_error`], is the only one that
32 //! requires mentioning [`utils::Error`](crate::Error) explicitly.  Similar
33 //! to how QEMU's C code handles errno values, the string and the
34 //! `anyhow::Error` object will be concatenated with `:` as the separator.
35 
36 use std::{
37     borrow::Cow,
38     ffi::{c_char, c_int, c_void, CStr},
39     fmt::{self, Display},
40     ops::Deref,
41     panic,
42     ptr::{self, addr_of_mut},
43 };
44 
45 use foreign::{prelude::*, OwnedPointer};
46 
47 use crate::bindings;
48 
49 pub type Result<T> = std::result::Result<T, Error>;
50 
51 #[derive(Debug)]
52 pub struct Error {
53     cause: anyhow::Error,
54     file: &'static str,
55     line: u32,
56 }
57 
58 impl Deref for Error {
59     type Target = anyhow::Error;
60 
61     fn deref(&self) -> &Self::Target {
62         &self.cause
63     }
64 }
65 
66 impl Display for Error {
67     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68         Display::fmt(&format_args!("{:#}", self.cause), f)
69     }
70 }
71 
72 impl<E> From<E> for Error
73 where
74     anyhow::Error: From<E>,
75 {
76     #[track_caller]
77     fn from(src: E) -> Self {
78         Self::new(anyhow::Error::from(src))
79     }
80 }
81 
82 impl Error {
83     /// Create a new error from an [`anyhow::Error`].
84     ///
85     /// This wraps the error with QEMU's location tracking information.
86     /// Most code should use the `?` operator instead of calling this directly.
87     #[track_caller]
88     pub fn new(cause: anyhow::Error) -> Self {
89         let location = panic::Location::caller();
90         Self {
91             cause,
92             file: location.file(),
93             line: location.line(),
94         }
95     }
96 
97     /// Create a new error from a string message.
98     ///
99     /// This is a convenience wrapper around [`Error::new`] for simple string
100     /// errors. Most code should use the [`ensure!`](crate::ensure) macro
101     /// instead of calling this directly.
102     #[track_caller]
103     pub fn msg(src: impl Into<Cow<'static, str>>) -> Self {
104         Self::new(anyhow::Error::msg(src.into()))
105     }
106 
107     #[track_caller]
108     #[doc(hidden)]
109     #[inline(always)]
110     pub fn format(args: fmt::Arguments) -> Self {
111         // anyhow::Error::msg will allocate anyway, might as well let fmt::format doit.
112         let msg = fmt::format(args);
113         Self::new(anyhow::Error::msg(msg))
114     }
115 
116     /// Create a new error, prepending `msg` to the
117     /// description of `cause`
118     #[track_caller]
119     pub fn with_error(msg: impl Into<Cow<'static, str>>, cause: impl Into<anyhow::Error>) -> Self {
120         fn do_with_error(
121             msg: Cow<'static, str>,
122             cause: anyhow::Error,
123             location: &'static panic::Location<'static>,
124         ) -> Error {
125             Error {
126                 cause: cause.context(msg),
127                 file: location.file(),
128                 line: location.line(),
129             }
130         }
131         do_with_error(msg.into(), cause.into(), panic::Location::caller())
132     }
133 
134     /// Consume a result, returning `false` if it is an error and
135     /// `true` if it is successful.  The error is propagated into
136     /// `errp` like the C API `error_propagate` would do.
137     ///
138     /// # Safety
139     ///
140     /// `errp` must be a valid argument to `error_propagate`;
141     /// typically it is received from C code and need not be
142     /// checked further at the Rust↔C boundary.
143     pub unsafe fn bool_or_propagate(result: Result<()>, errp: *mut *mut bindings::Error) -> bool {
144         // SAFETY: caller guarantees errp is valid
145         unsafe { Self::ok_or_propagate(result, errp) }.is_some()
146     }
147 
148     /// Consume a result, returning a `NULL` pointer if it is an error and
149     /// a C representation of the contents if it is successful.  This is
150     /// similar to the C API `error_propagate`, but it panics if `*errp`
151     /// is not `NULL`.
152     ///
153     /// # Safety
154     ///
155     /// `errp` must be a valid argument to `error_propagate`;
156     /// typically it is received from C code and need not be
157     /// checked further at the Rust↔C boundary.
158     ///
159     /// See [`propagate`](Error::propagate) for more information.
160     #[must_use]
161     pub unsafe fn ptr_or_propagate<T: CloneToForeign>(
162         result: Result<T>,
163         errp: *mut *mut bindings::Error,
164     ) -> *mut T::Foreign {
165         // SAFETY: caller guarantees errp is valid
166         unsafe { Self::ok_or_propagate(result, errp) }.clone_to_foreign_ptr()
167     }
168 
169     /// Consume a result in the same way as `self.ok()`, but also propagate
170     /// a possible error into `errp`.  This is similar to the C API
171     /// `error_propagate`, but it panics if `*errp` is not `NULL`.
172     ///
173     /// # Safety
174     ///
175     /// `errp` must be a valid argument to `error_propagate`;
176     /// typically it is received from C code and need not be
177     /// checked further at the Rust↔C boundary.
178     ///
179     /// See [`propagate`](Error::propagate) for more information.
180     pub unsafe fn ok_or_propagate<T>(
181         result: Result<T>,
182         errp: *mut *mut bindings::Error,
183     ) -> Option<T> {
184         result.map_err(|err| unsafe { err.propagate(errp) }).ok()
185     }
186 
187     /// Equivalent of the C function `error_propagate`.  Fill `*errp`
188     /// with the information container in `self` if `errp` is not NULL;
189     /// then consume it.
190     ///
191     /// This is similar to the C API `error_propagate`, but it panics if
192     /// `*errp` is not `NULL`.
193     ///
194     /// # Safety
195     ///
196     /// `errp` must be a valid argument to `error_propagate`; it can be
197     /// `NULL` or it can point to any of:
198     /// * `error_abort`
199     /// * `error_fatal`
200     /// * a local variable of (C) type `Error *`
201     ///
202     /// Typically `errp` is received from C code and need not be
203     /// checked further at the Rust↔C boundary.
204     pub unsafe fn propagate(self, errp: *mut *mut bindings::Error) {
205         if errp.is_null() {
206             return;
207         }
208 
209         // SAFETY: caller guarantees that errp and *errp are valid
210         unsafe {
211             assert_eq!(*errp, ptr::null_mut());
212             bindings::error_propagate(errp, self.clone_to_foreign_ptr());
213         }
214     }
215 
216     /// Pass a C `Error*` to the closure, and convert the result
217     /// (either the return value of the closure, or the error)
218     /// into a Rust `Result`.
219     ///
220     /// # Safety
221     ///
222     /// One exit from `f`, `c_error` must be unchanged or point to a
223     /// valid C [`struct Error`](bindings::Error).
224     pub unsafe fn with_errp<T, F: FnOnce(&mut *mut bindings::Error) -> T>(f: F) -> Result<T> {
225         let mut c_error: *mut bindings::Error = ptr::null_mut();
226 
227         // SAFETY: guaranteed by the postcondition of `f`
228         match (f(&mut c_error), unsafe { c_error.into_native() }) {
229             (result, None) => Ok(result),
230             (_, Some(err)) => Err(err),
231         }
232     }
233 }
234 
235 /// Extension trait for `std::result::Result`, providing extra
236 /// methods when the error type can be converted into a QEMU
237 /// Error.
238 pub trait ResultExt {
239     /// The success type `T` in `Result<T, E>`.
240     type OkType;
241 
242     /// Report a fatal error and exit QEMU, or return the success value.
243     /// Note that, unlike [`unwrap()`](std::result::Result::unwrap), this
244     /// is not an abort and can be used for user errors.
245     fn unwrap_fatal(self) -> Self::OkType;
246 }
247 
248 impl<T, E> ResultExt for std::result::Result<T, E>
249 where
250     Error: From<E>,
251 {
252     type OkType = T;
253 
254     fn unwrap_fatal(self) -> T {
255         // SAFETY: errp is valid
256         self.map_err(|err| unsafe {
257             Error::from(err).propagate(addr_of_mut!(bindings::error_fatal))
258         })
259         .unwrap()
260     }
261 }
262 
263 impl FreeForeign for Error {
264     type Foreign = bindings::Error;
265 
266     unsafe fn free_foreign(p: *mut bindings::Error) {
267         // SAFETY: caller guarantees p is valid
268         unsafe {
269             bindings::error_free(p);
270         }
271     }
272 }
273 
274 impl CloneToForeign for Error {
275     fn clone_to_foreign(&self) -> OwnedPointer<Self> {
276         // SAFETY: all arguments are controlled by this function
277         unsafe {
278             let err: *mut c_void = libc::malloc(std::mem::size_of::<bindings::Error>());
279             let err: &mut bindings::Error = &mut *err.cast();
280             *err = bindings::Error {
281                 msg: format!("{self}").clone_to_foreign_ptr(),
282                 err_class: bindings::ERROR_CLASS_GENERIC_ERROR,
283                 src_len: self.file.len() as c_int,
284                 src: self.file.as_ptr().cast::<c_char>(),
285                 line: self.line as c_int,
286                 func: ptr::null_mut(),
287                 hint: ptr::null_mut(),
288             };
289             OwnedPointer::new(err)
290         }
291     }
292 }
293 
294 impl FromForeign for Error {
295     unsafe fn cloned_from_foreign(c_error: *const bindings::Error) -> Self {
296         // SAFETY: caller guarantees c_error is valid
297         unsafe {
298             let error = &*c_error;
299             let file = if error.src_len < 0 {
300                 // NUL-terminated
301                 CStr::from_ptr(error.src).to_str()
302             } else {
303                 // Can become str::from_utf8 with Rust 1.87.0
304                 std::str::from_utf8(std::slice::from_raw_parts(
305                     &*error.src.cast::<u8>(),
306                     error.src_len as usize,
307                 ))
308             };
309 
310             Error {
311                 cause: anyhow::Error::msg(String::cloned_from_foreign(error.msg)),
312                 file: file.unwrap(),
313                 line: error.line as u32,
314             }
315         }
316     }
317 }
318 
319 /// Ensure that a condition is true, returning an error if it is false.
320 ///
321 /// This macro is similar to [`anyhow::ensure`] but returns a QEMU [`Result`].
322 /// If the condition evaluates to `false`, the macro returns early with an error
323 /// constructed from the provided message.
324 ///
325 /// # Examples
326 ///
327 /// ```
328 /// # use util::{ensure, Result};
329 /// # fn check_positive(x: i32) -> Result<()> {
330 /// ensure!(x > 0, "value must be positive");
331 /// #   Ok(())
332 /// # }
333 /// ```
334 ///
335 /// ```
336 /// # use util::{ensure, Result};
337 /// # const MIN: i32 = 123;
338 /// # const MAX: i32 = 456;
339 /// # fn check_range(x: i32) -> Result<()> {
340 /// ensure!(
341 ///     x >= MIN && x <= MAX,
342 ///     "{} not between {} and {}",
343 ///     x,
344 ///     MIN,
345 ///     MAX
346 /// );
347 /// #   Ok(())
348 /// # }
349 /// ```
350 #[macro_export]
351 macro_rules! ensure {
352     ($cond:expr, $fmt:literal, $($arg:tt)*) => {
353         if !$cond {
354             let e = $crate::Error::format(format_args!($fmt, $($arg)*));
355             return $crate::Result::Err(e);
356         }
357     };
358     ($cond:expr, $err:expr $(,)?) => {
359         if !$cond {
360             let e = $crate::Error::msg($err);
361             return $crate::Result::Err(e);
362         }
363     };
364 }
365 
366 #[cfg(test)]
367 mod tests {
368     use std::ffi::CStr;
369 
370     use anyhow::anyhow;
371     use common::assert_match;
372     use foreign::OwnedPointer;
373 
374     use super::*;
375 
376     #[track_caller]
377     fn error_for_test(msg: &CStr) -> OwnedPointer<Error> {
378         // SAFETY: all arguments are controlled by this function
379         let location = panic::Location::caller();
380         unsafe {
381             let err: *mut c_void = libc::malloc(std::mem::size_of::<bindings::Error>());
382             let err: &mut bindings::Error = &mut *err.cast();
383             *err = bindings::Error {
384                 msg: msg.clone_to_foreign_ptr(),
385                 err_class: bindings::ERROR_CLASS_GENERIC_ERROR,
386                 src_len: location.file().len() as c_int,
387                 src: location.file().as_ptr().cast::<c_char>(),
388                 line: location.line() as c_int,
389                 func: ptr::null_mut(),
390                 hint: ptr::null_mut(),
391             };
392             OwnedPointer::new(err)
393         }
394     }
395 
396     unsafe fn error_get_pretty<'a>(local_err: *mut bindings::Error) -> &'a CStr {
397         unsafe { CStr::from_ptr(bindings::error_get_pretty(local_err)) }
398     }
399 
400     #[test]
401     fn test_display() {
402         assert_eq!(&*format!("{}", Error::msg("msg")), "msg");
403         assert_eq!(&*format!("{}", Error::msg("msg".to_owned())), "msg");
404         assert_eq!(&*format!("{}", Error::from(anyhow!("msg"))), "msg");
405 
406         assert_eq!(
407             &*format!("{}", Error::with_error("msg", anyhow!("cause"))),
408             "msg: cause"
409         );
410     }
411 
412     #[test]
413     fn test_bool_or_propagate() {
414         unsafe {
415             let mut local_err: *mut bindings::Error = ptr::null_mut();
416 
417             assert!(Error::bool_or_propagate(Ok(()), &mut local_err));
418             assert_eq!(local_err, ptr::null_mut());
419 
420             let my_err = Error::msg("msg");
421             assert!(!Error::bool_or_propagate(Err(my_err), &mut local_err));
422             assert_ne!(local_err, ptr::null_mut());
423             assert_eq!(error_get_pretty(local_err), c"msg");
424             bindings::error_free(local_err);
425         }
426     }
427 
428     #[test]
429     fn test_ptr_or_propagate() {
430         unsafe {
431             let mut local_err: *mut bindings::Error = ptr::null_mut();
432 
433             let ret = Error::ptr_or_propagate(Ok("abc".to_owned()), &mut local_err);
434             assert_eq!(String::from_foreign(ret), "abc");
435             assert_eq!(local_err, ptr::null_mut());
436 
437             let my_err = Error::msg("msg");
438             assert_eq!(
439                 Error::ptr_or_propagate(Err::<String, _>(my_err), &mut local_err),
440                 ptr::null_mut()
441             );
442             assert_ne!(local_err, ptr::null_mut());
443             assert_eq!(error_get_pretty(local_err), c"msg");
444             bindings::error_free(local_err);
445         }
446     }
447 
448     #[test]
449     fn test_with_errp() {
450         unsafe {
451             let result = Error::with_errp(|_errp| true);
452             assert_match!(result, Ok(true));
453 
454             let err = Error::with_errp(|errp| {
455                 *errp = error_for_test(c"msg").into_inner();
456                 false
457             })
458             .unwrap_err();
459             assert_eq!(&*format!("{err}"), "msg");
460         }
461     }
462 }
463