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