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