1 use super::boxed::try_new_uninit_box; 2 use super::context::ContextError; 3 use super::ptr::{MutPtr, OwnedPtr, SharedPtr}; 4 use super::vtable::Vtable; 5 use crate::error::{OutOfMemory, Result}; 6 use core::{ 7 any::TypeId, 8 fmt::{self, Debug}, 9 iter::FusedIterator, 10 mem, 11 ptr::NonNull, 12 }; 13 #[cfg(feature = "backtrace")] 14 use std::backtrace::{Backtrace, BacktraceStatus}; 15 use std_alloc::boxed::Box; 16 17 /// Internal extension trait for errors. 18 /// 19 /// # Safety 20 /// 21 /// Safety relies on `ext_is` being implemented correctly. Implementations must 22 /// not lie about whether they are or are not an instance of the given type id's 23 /// associated type (or a newtype wrapper around that type). Violations will 24 /// lead to unsafety. 25 pub(crate) unsafe trait ErrorExt: Send + Sync + 'static { 26 /// Get this error as a shared reference to a `dyn core::error::Error` trait 27 /// object. 28 fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static); 29 30 /// Get this error as a boxed `dyn core::error::Error` trait object. 31 fn ext_into_boxed_dyn_core_error( 32 self, 33 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory>; 34 35 /// Get a shared borrow of the next error in the chain. 36 fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>>; 37 38 /// Get an exclusive borrow of the next error in the chain. 39 fn ext_source_mut(&mut self) -> Option<OomOrDynErrorMut<'_>>; 40 41 /// Take ownership of the next error in the chain. 42 fn ext_take_source(&mut self) -> Option<OomOrDynError>; 43 44 /// Is this error an instance of `T`, where `type_id == TypeId::of::<T>()` 45 /// or a newtype wrapper around that type? 46 /// 47 /// # Safety 48 /// 49 /// Implementations must return `true` only when they are actually a `T`, a 50 /// `#[repr(transparent)]` newtype wrapper around a `T`, or a `#[repr(C)]` 51 /// struct with a `T` as their first field. Safety relies on this invariant. 52 fn ext_is(&self, type_id: TypeId) -> bool; 53 54 /// Move the inner `T` error into the storage referenced by `dest`. 55 /// 56 /// # Safety 57 /// 58 /// Callers must ensure that `dest` is valid for writing a `T` to. 59 /// 60 /// Implementations must ensure that the memory block pointed to by `dest` 61 /// contains a valid, initialized `T` upon successful return. 62 unsafe fn ext_move(self, dest: NonNull<u8>); 63 64 /// Take the backtrace from this error, if any. 65 #[cfg(feature = "backtrace")] 66 fn take_backtrace(&mut self) -> Option<Backtrace>; 67 } 68 69 /// Morally a `dyn ErrorExt` trait object that holds its own vtable. 70 /// 71 /// Must only ever be used via some kind of indirection (pointer, reference, 72 /// `Box`, etc...) that is punning a `ConcreteError<?>` and never directly as an 73 /// on-stack value, for example. 74 /// 75 /// See the docs for `Vtable` for details about why we make our own trait 76 /// objects. 77 /// 78 /// XXX: Must have a compatible layout with `ConcreteError<E>`. See the 79 /// assertions in `BoxedDynError::new` and the 80 /// `dyn_error_and_concrete_error_layouts_are_compatible` test below. 81 #[repr(C)] 82 pub(crate) struct DynError { 83 // Safety: this vtable must always be associated with the `E` for the 84 // `ConcreteError<E>` that this `DynError` is punning. 85 pub(crate) vtable: &'static Vtable, 86 #[cfg(feature = "backtrace")] 87 pub(crate) backtrace: Option<Backtrace>, 88 // error: <?> 89 } 90 91 /// A `dyn ErrorExt` trait object that we know the concrete type of. 92 /// 93 /// XXX: Must have a compatible layout with `DynError`. See the 94 /// assertions in `BoxedDynError::new` and the 95 /// `dyn_error_and_concrete_error_layouts_are_compatible` test below. 96 #[repr(C)] 97 pub(crate) struct ConcreteError<E> { 98 // Safety: this vtable must always be `E`'s vtable. This is ensured in 99 // `BoxDynError::new`. 100 pub(crate) vtable: &'static Vtable, 101 #[cfg(feature = "backtrace")] 102 pub(crate) backtrace: Option<Backtrace>, 103 pub(crate) error: E, 104 } 105 106 pub(crate) struct BoxedDynError { 107 inner: OwnedPtr<DynError>, 108 } 109 110 // Safety: `BoxedDynError::new` ensures that every concrete error type we make a 111 // `BoxedDynError` from is `Send`. 112 unsafe impl Send for BoxedDynError {} 113 114 // Safety: `BoxedDynError::new` ensures that every concrete error type we make a 115 // `BoxedDynError` from is `Sync`. 116 unsafe impl Sync for BoxedDynError {} 117 118 impl Drop for BoxedDynError { 119 fn drop(&mut self) { 120 let ptr = self.inner.raw_copy(); 121 // Safety: We own the pointer and it is valid for reading/writing 122 // `DynError`s. 123 let inner = unsafe { ptr.as_ref() }; 124 let vtable = inner.vtable; 125 // Safety: The vtable is for this pointer's concrete type and the 126 // pointer is valid to deallocate because we are passing ownership in. 127 unsafe { 128 (vtable.drop_and_deallocate)(ptr); 129 } 130 } 131 } 132 133 impl BoxedDynError { 134 #[inline] 135 fn new<E>(mut error: E) -> Result<Self, OutOfMemory> 136 where 137 // NB: This implies `Send + Sync`, which is necessary for safety. 138 E: ErrorExt, 139 { 140 #[cfg(not(feature = "backtrace"))] 141 let _ = &mut error; 142 143 // Note: do not use `Option::or_else` here to avoid an extra frame 144 // showing up in the backtrace, which would create extra noise for users 145 // to mentally filter out. 146 #[cfg(feature = "backtrace")] 147 let backtrace = match error.take_backtrace() { 148 Some(bt) => bt, 149 None => crate::error::backtrace::capture(), 150 }; 151 152 let boxed = try_new_uninit_box()?; 153 let error = Box::write( 154 boxed, 155 ConcreteError { 156 vtable: Vtable::of::<E>(), 157 #[cfg(feature = "backtrace")] 158 backtrace: Some(backtrace), 159 error, 160 }, 161 ); 162 163 // We are going to pun the `ConcreteError<E>` pointer into a `DynError` 164 // pointer. Debug assert that their layouts are compatible first. 165 #[cfg(debug_assertions)] 166 { 167 let dyn_size = mem::size_of::<DynError>(); 168 let concrete_size = mem::size_of::<ConcreteError<E>>(); 169 assert!( 170 dyn_size <= concrete_size, 171 "assertion failed: {dyn_size} <= {concrete_size}" 172 ); 173 174 let dyn_align = mem::align_of::<DynError>(); 175 let concrete_align = mem::align_of::<ConcreteError<E>>(); 176 assert!( 177 dyn_align <= concrete_align, 178 "assertion failed: {dyn_align} <= {concrete_align}" 179 ); 180 181 let dyn_offset = mem::offset_of!(DynError, vtable); 182 let concrete_offset = mem::offset_of!(ConcreteError<E>, vtable); 183 assert_eq!(dyn_offset, concrete_offset); 184 185 #[cfg(feature = "backtrace")] 186 { 187 let dyn_offset = mem::offset_of!(DynError, backtrace); 188 let concrete_offset = mem::offset_of!(ConcreteError<E>, backtrace); 189 assert_eq!(dyn_offset, concrete_offset); 190 } 191 } 192 193 let ptr = Box::into_raw(error); 194 let ptr = ptr.cast::<DynError>(); 195 // Safety: `Box::into_raw` always returns a non-null pointer. 196 let ptr = unsafe { NonNull::new_unchecked(ptr) }; 197 let ptr = OwnedPtr::new(ptr); 198 // Safety: points to a valid `DynError`. 199 Ok(unsafe { Self::from_owned_ptr(ptr) }) 200 } 201 202 fn into_owned_ptr(self) -> OwnedPtr<DynError> { 203 let ptr = self.inner.raw_copy(); 204 mem::forget(self); 205 ptr 206 } 207 208 /// # Safety 209 /// 210 /// The given pointer must be a valid `DynError` pointer: punning a 211 /// `ConcreteError<?>` and is safe to drop and deallocate with its 212 /// `DynError::vtable` methods. 213 unsafe fn from_owned_ptr(inner: OwnedPtr<DynError>) -> Self { 214 BoxedDynError { inner } 215 } 216 } 217 218 /// Wasmtime's universal error type. 219 /// 220 /// 99% API-compatible with `anyhow::Error` but additionally allows recovery 221 /// from memory exhaustion (see the [`OutOfMemory`] error). 222 /// 223 /// `Error` is similar to `Box<dyn core::error::Error + Send + Sync + 'static>` 224 /// but fits in one word instead of two. Additionally, `Result<(), Error>` also 225 /// fits in a single word. 226 /// 227 /// When the `"backtrace"` cargo feature is enabled, `Error` contains a 228 /// backtrace. 229 /// 230 /// # Creating an `Error` 231 /// 232 /// Because `Error` implements `From<E>` for all types `E` that implement 233 /// `core::error::Error + Send + Sync + 'static`, you don't usually need to 234 /// explicitly construct an `Error`. When you use `?`-style error propagation, 235 /// it will automatically get constructed from the root cause error for you. 236 /// 237 /// Most often when creating an `Error`, you just want to early-exit from the 238 /// function, returning `Err(...)`. The [`ensure!`](crate::ensure) macro 239 /// early-returns an error when a condition is not met (similar to how `assert!` 240 /// panics when a condition is not met) and the [`bail!`](crate::bail) macro 241 /// early-returns an error unconditionally. 242 /// 243 /// ``` 244 /// # use wasmtime_internal_core::error as wasmtime; 245 /// use wasmtime::{bail, ensure, Result}; 246 /// 247 /// fn my_fallible_function(x: u32) -> Result<()> { 248 /// // This `ensure!` macro invocation is equivalent to 249 /// // 250 /// // if x % 2 != 0 { 251 /// // return Err(...); 252 /// // } 253 /// ensure!(x % 2 == 0, "{x} is not even!"); 254 /// 255 /// // This `bail!` macro invocation is equivalent to 256 /// // 257 /// // return Err(...); 258 /// bail!("oops, another error! {x}") 259 /// } 260 /// ``` 261 /// 262 /// If you do not want to early-return, just to create the `Error`, then the 263 /// [`format_err!`](crate::format_err) macro is preferred: 264 /// 265 /// ``` 266 /// # use wasmtime_internal_core::error as wasmtime; 267 /// use wasmtime::{format_err, Error}; 268 /// 269 /// let x = 42; 270 /// let my_error: Error = format_err!("whoops! {x}"); 271 /// ``` 272 /// 273 /// If, however, you happen to require a constructor function instead of a 274 /// macro, you can use either [`Error::new`] or [`Error::msg`]: 275 /// 276 /// ``` 277 /// # use wasmtime_internal_core::error as wasmtime; 278 /// use wasmtime::Error; 279 /// 280 /// let messages = ["yikes", "uh oh", "ouch"]; 281 /// let errors = messages 282 /// .into_iter() 283 /// .map(Error::msg) 284 /// .collect::<Vec<_>>(); 285 /// ``` 286 /// 287 /// # Printing an `Error` 288 /// 289 /// Different format strings will print an `Error` differently: 290 /// 291 /// * `{}`: Prints the `Display` of just the first error, without any of the 292 /// other errors in the chain or the root cause. 293 /// 294 /// * `{:#}`: Prints the `Display` of the first error, then (if there are more 295 /// errors in the chain) a colon, then the display of the second error in the 296 /// chain, etc... 297 /// 298 /// * `{:?}`: Prints the `Display` of the first error, then (if there are more 299 /// errors in the chain) a newline-separated list of the rest of the errors in 300 /// the chain, and finally (if the `"backtrace"` cargo feature is enabled, the 301 /// `RUST_BACKTRACE` environment variable is set and non-zero, and the 302 /// platform is supported by Rust's standard library's `Backtrace` type) the 303 /// captured backtrace is printed. 304 /// 305 /// This is the default formatting used when `fn main() -> 306 /// wasmtime::Result<()>` returns an error. 307 /// 308 /// * `{:#?}`: Prints an internal, debugging representation of the `Error`. We 309 /// make no guarantees about its stability. 310 /// 311 /// Here is an example showing the different formats for the same error: 312 /// 313 /// ``` 314 /// # fn _foo() { 315 /// #![cfg(all(feature = "backtrace", not(miri)))] 316 /// # let _ = unsafe { std::env::set_var("RUST_BACKTRACE", "1") }; 317 /// # use wasmtime_internal_core as wasmtime; 318 /// use wasmtime::error::{bail, Context as _, Result}; 319 /// 320 /// fn uno() -> Result<()> { 321 /// bail!("ouch") 322 /// } 323 /// 324 /// fn dos() -> Result<()> { 325 /// uno().context("whoops") 326 /// } 327 /// 328 /// fn tres() -> Result<()> { 329 /// dos().context("uh oh") 330 /// } 331 /// 332 /// let error = tres().unwrap_err(); 333 /// 334 /// println!("{error}"); 335 /// // Prints: 336 /// // 337 /// // uh oh 338 /// 339 /// println!("{error:#}"); 340 /// // Prints: 341 /// // 342 /// // uh oh: whoops: ouch 343 /// 344 /// println!("{error:?}"); 345 /// // Prints 346 /// // 347 /// // uh oh 348 /// // 349 /// // Caused by: 350 /// // 0: whoops 351 /// // 1: ouch 352 /// // 353 /// // Stack backtrace: 354 /// // <...> 355 /// // 7: example::uno 356 /// // 8: example::dos 357 /// // 9: example::tres 358 /// // 10: example::main 359 /// // <...> 360 /// 361 /// println!("{error:#?}"); 362 /// // Prints 363 /// // 364 /// // Error { 365 /// // <...> 366 /// // } 367 /// # } 368 /// ``` 369 /// 370 /// # Converting a `wasmtime::Error` into an `anyhow::Error` 371 /// 372 /// When the `"anyhow"` feature is enabled, there is a `From<wasmtime::Error> 373 /// for anyhow::Error` implementation. You can always call that implementation 374 /// explicitly if needed, but `?`-propagation allows the conversion to happen 375 /// seamlessly from functions that return a `Result<T, wasmtime::Error>` to 376 /// those that return a `Result<U, anyhow::Error>`. 377 /// 378 /// ``` 379 /// # fn _foo() { 380 /// #![cfg(feature = "anyhow")] 381 /// # use wasmtime_internal_core::error as wasmtime; 382 /// 383 /// fn foo() -> Result<(), wasmtime::Error> { 384 /// wasmtime::bail!("decontamination failure") 385 /// } 386 /// 387 /// fn bar() -> Result<(), anyhow::Error> { 388 /// foo()?; // `?` is auto-converting here! 389 /// Ok(()) 390 /// } 391 /// 392 /// let error = bar().unwrap_err(); 393 /// assert_eq!(error.to_string(), "decontamination failure"); 394 /// # } 395 /// ``` 396 /// 397 /// # Converting an `anyhow::Error` into a `wasmtime::Error` 398 /// 399 /// When the `"anyhow"` feature is enabled, there is an `Error::from_anyhow` 400 /// constructor that you may use to convert an `anyhow::Error` into a 401 /// `wasmtime::Error`. (Unfortunately trait coherence does not allow us a 402 /// `From<anyhow::Error> for wasmtime::Error` implementation.) This will 403 /// most-often be used in combination with `Result::map_err`: 404 /// 405 /// ``` 406 /// # fn _foo() { 407 /// #![cfg(feature = "anyhow")] 408 /// # use wasmtime_internal_core::error as wasmtime; 409 /// 410 /// fn baz() -> Result<(), anyhow::Error> { 411 /// anyhow::bail!("oops I ate worms") 412 /// } 413 /// 414 /// fn qux() -> Result<(), wasmtime::Error> { 415 /// baz().map_err(wasmtime::Error::from_anyhow)?; 416 /// Ok(()) 417 /// } 418 /// 419 /// let error = qux().unwrap_err(); 420 /// assert_eq!(error.to_string(), "oops I ate worms"); 421 /// # } 422 /// ``` 423 #[repr(transparent)] 424 pub struct Error { 425 pub(crate) inner: OomOrDynError, 426 } 427 428 /// For performance, it is important that `Error` and `Result<()>` fit in a 429 /// single word so that they can be passed in registers by rustc/llvm, rather 430 /// than on the stack, when used as a function's return type. 431 const _ERROR_IS_ONE_WORD_LARGE: () = assert!(mem::size_of::<Error>() == mem::size_of::<usize>()); 432 const _RESULT_OF_UNIT_IS_ONE_WORD_LARGE: () = 433 assert!(mem::size_of::<Result<()>>() == mem::size_of::<usize>()); 434 435 impl fmt::Debug for Error { 436 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 437 if f.alternate() { 438 return f 439 .debug_struct("Error") 440 .field("inner", &self.inner.unpack()) 441 .finish(); 442 } 443 444 let inner = self.inner.unpack(); 445 inner.display(f)?; 446 447 if let Some(source) = inner.source() { 448 f.write_str("\n\nCaused by:\n")?; 449 let multiple_causes = source.source().is_some(); 450 for (i, e) in Chain::new(source).enumerate() { 451 if multiple_causes { 452 write!(f, "{i: >5}: ")?; 453 } else { 454 write!(f, " ")?; 455 } 456 writeln!(f, "{e}")?; 457 } 458 } 459 460 #[cfg(feature = "backtrace")] 461 { 462 let backtrace = inner.backtrace(); 463 if let BacktraceStatus::Captured = backtrace.status() { 464 f.write_str("\nStack backtrace:\n")?; 465 fmt::Display::fmt(backtrace, f)?; 466 } 467 } 468 469 Ok(()) 470 } 471 } 472 473 impl fmt::Display for Error { 474 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 475 let inner = self.inner.unpack(); 476 inner.display(f)?; 477 478 if f.alternate() { 479 if let Some(e) = inner.source() { 480 for e in Chain::new(e) { 481 write!(f, ": {e}")?; 482 } 483 } 484 } 485 486 Ok(()) 487 } 488 } 489 490 impl<E> From<E> for Error 491 where 492 E: core::error::Error + Send + Sync + 'static, 493 { 494 fn from(error: E) -> Self { 495 Self::new(error) 496 } 497 } 498 499 impl From<Error> for Box<dyn core::error::Error + Send + Sync + 'static> { 500 #[inline] 501 fn from(error: Error) -> Self { 502 error.into_boxed_dyn_error() 503 } 504 } 505 506 impl From<Error> for Box<dyn core::error::Error + Send + 'static> { 507 #[inline] 508 fn from(error: Error) -> Self { 509 error.into_boxed_dyn_error() 510 } 511 } 512 513 impl From<Error> for Box<dyn core::error::Error + 'static> { 514 #[inline] 515 fn from(error: Error) -> Self { 516 error.into_boxed_dyn_error() 517 } 518 } 519 520 /// Convert a [`wasmtime::Error`](Error) into an [`anyhow::Error`]. 521 /// 522 /// # Example 523 /// 524 /// ``` 525 /// # use wasmtime_internal_core::error as wasmtime; 526 /// let wasmtime_error = wasmtime::Error::msg("whoops"); 527 /// let anyhow_error = anyhow::Error::from(wasmtime_error); 528 /// ``` 529 // 530 // Unfortunately, we can't also implement `From<anyhow::Error> for Error` 531 // because of trait coherence. From Rust's trait system's point of view, 532 // `anyhow` could theoretically add an `core::error::Error for anyhow::Error` 533 // implementation, which would make our desired `From<anyhow::Error>` 534 // implementation conflict with our existing `From<E: core::error::Error>` 535 // implementation. They cannot in fact add that implementation, however, because 536 // they already have a `From<E: core::error::Error> for anyhow::Error` 537 // implementation and so adding `core::error::Error for anyhow::Error` would 538 // cause that impl to conflict with `From<T> for T` (which is the same reason we 539 // cannot implement `core::error::Error for Error`). Nonetheless, our hands are 540 // tied here. 541 #[cfg(feature = "anyhow")] 542 impl From<Error> for anyhow::Error { 543 #[inline] 544 fn from(e: Error) -> Self { 545 anyhow::Error::from_boxed(e.into_boxed_dyn_error()) 546 } 547 } 548 549 impl core::ops::Deref for Error { 550 type Target = dyn core::error::Error + Send + Sync + 'static; 551 552 fn deref(&self) -> &Self::Target { 553 self.as_ref() 554 } 555 } 556 557 impl AsRef<dyn core::error::Error> for Error { 558 #[inline] 559 fn as_ref(&self) -> &(dyn core::error::Error + 'static) { 560 self.inner.unpack().as_dyn_core_error() 561 } 562 } 563 564 impl AsRef<dyn core::error::Error + Send + Sync> for Error { 565 #[inline] 566 fn as_ref(&self) -> &(dyn core::error::Error + Send + Sync + 'static) { 567 self.inner.unpack().as_dyn_core_error() 568 } 569 } 570 571 impl Error { 572 /// Construct a new `Error` from a type that implements 573 /// `core::error::Error`. 574 /// 575 /// Calling [`error.is::<E>()`](Error::is) will return `true` for the new 576 /// error (unless there was a memory allocation failure). 577 /// 578 /// This boxes the inner error, but if that box allocation fails, then this 579 /// function returns an `Error` where 580 /// [`error.is::<OutOfMemory>()`](OutOfMemory) is true. 581 /// 582 /// # Example 583 /// 584 /// ``` 585 /// # use wasmtime_internal_core::error as wasmtime; 586 /// use wasmtime::Error; 587 /// 588 /// let error = Error::new(std::fmt::Error); 589 /// ``` 590 pub fn new<E>(error: E) -> Self 591 where 592 E: core::error::Error + Send + Sync + 'static, 593 { 594 if TypeId::of::<E>() == TypeId::of::<OutOfMemory>() { 595 // Although we know that `E == OutOfMemory` in this block, the 596 // compiler doesn't understand that, and we have to do this litle 597 // dance. 598 union ToOom<T> { 599 oom: OutOfMemory, 600 error: mem::ManuallyDrop<T>, 601 } 602 let error = mem::ManuallyDrop::new(error); 603 // Safety: `E == OutOfMemory`. 604 let oom = unsafe { (ToOom { error }).oom }; 605 return Error { inner: oom.into() }; 606 } 607 608 Self::from_error_ext(ForeignError(error)) 609 } 610 611 /// Construct a new `Error` from any type that implements `Debug` and 612 /// `Display`. 613 /// 614 /// Calling [`error.is::<M>()`](Error::is) will return `true` for the new 615 /// error (unless there was a memory allocation failure). 616 /// 617 /// This boxes the inner `M` type, but if that box allocation fails, then 618 /// this function returns an `Error` where 619 /// [`error.is::<OutOfMemory>()`](OutOfMemory) is true. 620 /// 621 /// # Example 622 /// 623 /// ``` 624 /// # use wasmtime_internal_core::error as wasmtime; 625 /// use wasmtime::Error; 626 /// 627 /// let error = Error::msg("hello"); 628 /// ``` 629 pub fn msg<M>(message: M) -> Self 630 where 631 M: fmt::Debug + fmt::Display + Send + Sync + 'static, 632 { 633 Self::from_error_ext(MessageError(message)) 634 } 635 636 /// Create an `Error` from a `Box<dyn core::error::Error>`. 637 /// 638 /// This is useful when converting errors from other universal-error 639 /// libraries into this crate's `Error` type. Prefer [`Error::from_anyhow`] 640 /// for converting `anyhow::Error`s into `Error`s, as that preserves 641 /// `error.is::<anyhow::Error>()`. 642 /// 643 /// Calling [`error.is::<Box<dyn core::error::Error + Send + Sync + 644 /// 'static>>()`](Error::is) will return `true` for the new error (unless 645 /// there was a memory allocation failure). 646 /// 647 /// This reboxes the inner error, but if that box allocation fails, then 648 /// this function returns an `Error` where 649 /// [`error.is::<OutOfMemory>()`](OutOfMemory) is true. 650 /// 651 /// # Example 652 /// 653 /// ``` 654 /// # fn _foo() { 655 /// #![cfg(all(feature = "std", feature = "anyhow"))] 656 /// # use wasmtime_internal_core::error as wasmtime; 657 /// use std::error::Error; 658 /// 659 /// // You happen to have a boxed error trait object. 660 /// let orig_error = std::fs::read("XXX: some file that doesn't exist").unwrap_err(); 661 /// let boxed_error: Box<dyn Error + Send + Sync + 'static> = Box::new(orig_error) as _; 662 /// 663 /// // You can turn it into a `wasmtime::Error` via `from_boxed`. 664 /// let wasmtime_error = wasmtime::Error::from_boxed(boxed_error); 665 /// # } 666 /// ``` 667 pub fn from_boxed(error: Box<dyn core::error::Error + Send + Sync + 'static>) -> Self { 668 Self::from_error_ext(BoxedError(error)) 669 } 670 671 /// Convert an `anyhow::Error` into an `Error`. 672 /// 673 /// Calling [`error.is::<anyhow::Error>()`](Error::is) will return `true` 674 /// for the new error (unless there was a memory allocation failure). 675 /// 676 /// This reboxes the `anyhow::Error`, but if that box allocation fails, then 677 /// this function returns an `Error` where 678 /// [`error.is::<OutOfMemory>()`](OutOfMemory) is true. 679 /// 680 /// # Example 681 /// 682 /// ``` 683 /// # fn _foo() { 684 /// #![cfg(all(feature = "std", feature = "anyhow"))] 685 /// # use wasmtime_internal_core::error as wasmtime; 686 /// let anyhow_error = anyhow::Error::msg("failed to flim the flam"); 687 /// let wasmtime_error = wasmtime::Error::from_anyhow(anyhow_error); 688 /// assert_eq!( 689 /// wasmtime_error.to_string(), 690 /// "failed to flim the flam", 691 /// ); 692 /// # } 693 /// ``` 694 #[cfg(feature = "anyhow")] 695 #[inline] 696 pub fn from_anyhow(error: anyhow::Error) -> Self { 697 Self::from_error_ext(AnyhowError(error)) 698 } 699 700 /// Add additional context to this error. 701 /// 702 /// The new context will show up first in the error chain, and the original 703 /// error will come next. 704 /// 705 /// This is similar to the [`Context::context`] trait method, but because it 706 /// is a method directly on [`Error`], there is no need for lazily-computing 707 /// the error context (like `with_context` does). 708 /// 709 /// Calling [`error.is::<C>()`](Error::is) will return `true` for the new 710 /// error (unless there was a memory allocation failure) in addition to any 711 /// other types `T` for which it was already the case that 712 /// `error.is::<T>()`. 713 /// 714 /// This boxes the inner `C` type, but if that box allocation fails, then 715 /// this function returns an `Error` where 716 /// [`error.is::<OutOfMemory>()`](OutOfMemory) is true. 717 /// 718 /// [`Context::context`]: crate::error::Context::context 719 /// 720 /// # Example 721 /// 722 /// ``` 723 /// # use wasmtime_internal_core::error as wasmtime; 724 /// use wasmtime::Error; 725 /// 726 /// let error = Error::msg("root cause"); 727 /// let error = error.context("failed to bonkinate"); 728 /// let error = error.context("cannot frob the blobbins"); 729 /// 730 /// assert!( 731 /// format!("{error:?}").contains( 732 /// r#" 733 /// cannot frob the blobbins 734 /// 735 /// Caused by: 736 /// 0: failed to bonkinate 737 /// 1: root cause 738 /// "#.trim(), 739 /// ), 740 /// ); 741 /// ``` 742 pub fn context<C>(self, context: C) -> Self 743 where 744 C: fmt::Display + Send + Sync + 'static, 745 { 746 if self.inner.is_oom() { 747 self 748 } else { 749 Self::from_error_ext(ContextError { 750 context, 751 error: Some(self), 752 }) 753 } 754 } 755 756 #[inline] 757 pub(crate) fn from_error_ext(error: impl ErrorExt) -> Self { 758 match BoxedDynError::new(error) { 759 Ok(boxed) => Error { 760 inner: boxed.into(), 761 }, 762 Err(oom) => Error { inner: oom.into() }, 763 } 764 } 765 766 /// Get this error's backtrace. 767 /// 768 /// Backtraces will be automatically captured on initial `Error` creation 769 /// when all of the following conditions are met: 770 /// 771 /// * This crate's `"backtrace"` cargo feature is enabled 772 /// * Rust's `std::backtrace::Backtrace` supports the platform 773 /// * The `RUST_BACKTRACE` or `RUST_LIB_BACKTRACE` environment variables 774 /// are set and non-zero 775 /// 776 /// See [the `std::backtrace::Backtrace` 777 /// documentation](https://doc.rust-lang.org/stable/std/backtrace/struct.Backtrace.html) 778 /// for more details on backtraces. 779 /// 780 /// Note that `std::backtrace::Backtrace` does not provide a 781 /// fallible-capture mechanism that returns an error, rather than aborting 782 /// the process, when it encounters memory exhaustion. If you require 783 /// out-of-memory error handling, do not enable this crate's `"backtrace"` 784 /// cargo feature. 785 /// 786 /// # Example 787 /// 788 /// ``` 789 /// # fn _foo() { 790 /// #![cfg(feature = "backtrace")] 791 /// # use wasmtime_internal_core::error as wasmtime; 792 /// use std::backtrace::BacktraceStatus; 793 /// use wasmtime::Error; 794 /// 795 /// let error = Error::msg("whoops"); 796 /// 797 /// let backtrace = error.backtrace(); 798 /// if let BacktraceStatus::Captured = backtrace.status() { 799 /// println!("error backtrace is:\n{backtrace}"); 800 /// } 801 /// # } 802 /// ``` 803 #[inline] 804 #[cfg(feature = "backtrace")] 805 pub fn backtrace(&self) -> &Backtrace { 806 self.inner.unpack().backtrace() 807 } 808 809 /// Iterate over this error's context chain. 810 /// 811 /// The iterator yields `&(dyn core::error::Error + 'static)` items. 812 /// 813 /// Iterates from the most recently added error context towards the root 814 /// cause. 815 /// 816 /// # Example 817 /// 818 /// ``` 819 /// # use wasmtime_internal_core::error as wasmtime; 820 /// use wasmtime::Error; 821 /// 822 /// let error = Error::msg("root cause"); 823 /// let error = error.context("failed to reticulate splines"); 824 /// let error = error.context("aborting launch"); 825 /// 826 /// let messages: Vec<_> = error.chain().map(|e| e.to_string()).collect(); 827 /// assert_eq!( 828 /// messages, 829 /// ["aborting launch", "failed to reticulate splines", "root cause"], 830 /// ); 831 /// ``` 832 #[inline] 833 pub fn chain(&self) -> Chain<'_> { 834 Chain::new(self.inner.unpack()) 835 } 836 837 /// Get the last error in the context chain. 838 /// 839 /// # Example 840 /// 841 /// ``` 842 /// # use wasmtime_internal_core::error as wasmtime; 843 /// use wasmtime::Error; 844 /// 845 /// let error = Error::msg("ghosts"); 846 /// let error = error.context("failed to reticulate splines"); 847 /// let error = error.context("aborting launch"); 848 /// 849 /// assert_eq!( 850 /// error.root_cause().to_string(), 851 /// "ghosts", 852 /// ); 853 /// ``` 854 #[inline] 855 pub fn root_cause(&self) -> &(dyn core::error::Error + 'static) { 856 self.chain().last().expect("chain is always non-empty") 857 } 858 859 /// Is this an `E` error? 860 /// 861 /// Returns true if any error in the context chain is an `E`. 862 /// 863 /// # Example 864 /// 865 /// ``` 866 /// # use wasmtime_internal_core as wasmtime; 867 /// use wasmtime::error::{Error, OutOfMemory}; 868 /// 869 /// let oom = Error::from(OutOfMemory::new(1234)); 870 /// assert!(oom.is::<OutOfMemory>()); 871 /// assert!(!oom.is::<std::num::TryFromIntError>()); 872 /// 873 /// // Here is an example with additional error context. 874 /// let error = Error::from(u8::try_from(u32::MAX).unwrap_err()); 875 /// let error = error.context(format!("cannot convert {} into a u8", u32::MAX)); 876 /// assert!( 877 /// error.is::<std::num::TryFromIntError>(), 878 /// "root cause is an int conversion failure", 879 /// ); 880 /// assert!( 881 /// error.is::<String>(), 882 /// "additional context is a `String`", 883 /// ); 884 /// assert!( 885 /// !error.is::<OutOfMemory>(), 886 /// "no error in the chain is an out-of-memory error", 887 /// ); 888 /// ``` 889 pub fn is<E>(&self) -> bool 890 where 891 E: fmt::Display + fmt::Debug + Send + Sync + 'static, 892 { 893 let mut error = Some(self.inner.unpack()); 894 while let Some(e) = error { 895 if e.is::<E>() { 896 return true; 897 } else { 898 error = e.source(); 899 } 900 } 901 false 902 } 903 904 /// Downcast this error into an `E`, taking ownership. 905 /// 906 /// If this error is an `E`, then `Ok(E)` is returned. Otherwise, 907 /// `Err(self)` is returned. 908 /// 909 /// If there are multiple instances of `E` in this error's chain, then the 910 /// first (as encountered by [`Error::chain`]'s iteration order) is 911 /// returned. 912 /// 913 /// # Example 914 /// 915 /// ``` 916 /// # use wasmtime_internal_core as wasmtime; 917 /// use wasmtime::error::{Error, OutOfMemory}; 918 /// 919 /// let error = Error::msg("whoops"); 920 /// 921 /// // `error` is not an `OutOfMemory`. 922 /// let downcasted = error.downcast::<OutOfMemory>(); 923 /// assert!(downcasted.is_err()); 924 /// 925 /// // Get the original `error` back. 926 /// let error = downcasted.unwrap_err(); 927 /// 928 /// // `error` is an `&str`. 929 /// let downcasted = error.downcast::<&str>(); 930 /// assert!(downcasted.is_ok()); 931 /// assert_eq!(downcasted.unwrap(), "whoops"); 932 /// 933 /// // If there are multiple `E`s in the chain, the first in the chain is 934 /// // returned. 935 /// let error = Error::msg("root cause"); 936 /// let error = error.context("failed to recombobulate"); 937 /// assert_eq!( 938 /// error.downcast::<&str>().unwrap(), 939 /// "failed to recombobulate", 940 /// ); 941 /// ``` 942 pub fn downcast<E>(self) -> Result<E, Self> 943 where 944 E: fmt::Display + fmt::Debug + Send + Sync + 'static, 945 { 946 if !self.is::<E>() { 947 return Err(self); 948 } 949 950 let mut value = mem::MaybeUninit::<E>::uninit(); 951 952 // Safety: this error is an `E` and the given pointer is valid to write 953 // an `E` to. 954 unsafe { 955 self.inner 956 .downcast(TypeId::of::<E>(), NonNull::from(&mut value).cast::<u8>()); 957 } 958 959 // Safety: `OomOrDynError::downcast` guarantees that the given pointer's 960 // data is initialized upon successful return. 961 Ok(unsafe { value.assume_init() }) 962 } 963 964 /// Downcast this error into a shared `&E` borrow. 965 /// 966 /// If this error is an `E`, then `Some(&E)` is returned. Otherwise, `None` 967 /// is returned. 968 /// 969 /// If there are multiple instances of `E` in this error's chain, then the 970 /// first (as encountered by [`Error::chain`]'s iteration order) is 971 /// returned. 972 /// 973 /// # Example 974 /// 975 /// ``` 976 /// # use wasmtime_internal_core as wasmtime; 977 /// use wasmtime::error::{Error, OutOfMemory}; 978 /// 979 /// let error = Error::msg("whoops"); 980 /// 981 /// // `error` is not an `OutOfMemory`. 982 /// assert!(error.downcast_ref::<OutOfMemory>().is_none()); 983 /// 984 /// // `error` is an `&str`. 985 /// assert!(error.downcast_ref::<&str>().is_some()); 986 /// assert_eq!(*error.downcast_ref::<&str>().unwrap(), "whoops"); 987 /// 988 /// // If there are multiple `E`s in the chain, the first in the chain is 989 /// // returned. 990 /// let error = Error::msg("root cause"); 991 /// let error = error.context("failed to recombobulate"); 992 /// assert_eq!( 993 /// *error.downcast_ref::<&str>().unwrap(), 994 /// "failed to recombobulate", 995 /// ); 996 /// ``` 997 pub fn downcast_ref<E>(&self) -> Option<&E> 998 where 999 E: fmt::Display + fmt::Debug + Send + Sync + 'static, 1000 { 1001 let mut error = Some(self.inner.unpack()); 1002 while let Some(e) = error { 1003 if e.is::<E>() { 1004 return Some(match e { 1005 OomOrDynErrorRef::DynError(ptr) => { 1006 let ptr = ptr.cast::<ConcreteError<E>>(); 1007 // Safety: we own the pointer, it is valid for reading, 1008 // and we checked that it is an `E`. 1009 let r = unsafe { ptr.as_ref() }; 1010 &r.error 1011 } 1012 OomOrDynErrorRef::Oom(oom) => { 1013 // Note: Even though we know that `E == OutOfMemory` 1014 // here, we still have to do this dance to satisfy the 1015 // type system. 1016 debug_assert_eq!(TypeId::of::<E>(), TypeId::of::<OutOfMemory>()); 1017 let ptr = NonNull::from(oom); 1018 let ptr = ptr.cast::<E>(); 1019 // Safety: the pointer points to `oom`, which is valid 1020 // for creating a shared reference to. 1021 unsafe { ptr.as_ref() } 1022 } 1023 }); 1024 } else { 1025 error = e.source(); 1026 } 1027 } 1028 None 1029 } 1030 1031 /// Downcast this error into an exclusive `&mut E` borrow. 1032 /// 1033 /// If this error is an `E`, then `Some(&mut E)` is returned. Otherwise, 1034 /// `None` is returned. 1035 /// 1036 /// If there are multiple instances of `E` in this error's chain, then the 1037 /// first (as encountered by [`Error::chain`]'s iteration order) is 1038 /// returned. 1039 /// 1040 /// # Example 1041 /// 1042 /// ``` 1043 /// # use wasmtime_internal_core as wasmtime; 1044 /// use wasmtime::error::{Error, OutOfMemory}; 1045 /// 1046 /// let mut error = Error::msg("whoops"); 1047 /// 1048 /// // `error` is not an `OutOfMemory`. 1049 /// assert!(error.downcast_mut::<OutOfMemory>().is_none()); 1050 /// 1051 /// // `error` is an `&str`. 1052 /// assert!(error.downcast_mut::<&str>().is_some()); 1053 /// assert_eq!(*error.downcast_mut::<&str>().unwrap(), "whoops"); 1054 /// *error.downcast_mut::<&str>().unwrap() = "yikes"; 1055 /// assert_eq!(*error.downcast_mut::<&str>().unwrap(), "yikes"); 1056 /// 1057 /// // If there are multiple `E`s in the chain, the first in the chain is 1058 /// // returned. 1059 /// let error = Error::msg("root cause"); 1060 /// let mut error = error.context("failed to recombobulate"); 1061 /// assert_eq!( 1062 /// *error.downcast_mut::<&str>().unwrap(), 1063 /// "failed to recombobulate", 1064 /// ); 1065 /// ``` 1066 pub fn downcast_mut<E>(&mut self) -> Option<&mut E> 1067 where 1068 E: fmt::Display + fmt::Debug + Send + Sync + 'static, 1069 { 1070 let mut error = Some(self.inner.unpack_mut()); 1071 while let Some(mut e) = error.take() { 1072 if e.as_ref().is::<E>() { 1073 return Some(match e { 1074 OomOrDynErrorMut::DynError(ptr) => { 1075 let mut ptr = ptr.cast::<ConcreteError<E>>(); 1076 // Safety: we own the pointer, it is valid for reading 1077 // and writing, and we checked that it is an `E`. 1078 let r = unsafe { ptr.as_mut() }; 1079 &mut r.error 1080 } 1081 OomOrDynErrorMut::Oom(oom) => { 1082 // Note: Even though we know that `E == OutOfMemory` 1083 // here, we still have to do this dance to satisfy the 1084 // type system. 1085 debug_assert_eq!(TypeId::of::<E>(), TypeId::of::<OutOfMemory>()); 1086 let ptr = NonNull::from(oom); 1087 let mut ptr = ptr.cast::<E>(); 1088 // Safety: the pointer points to `oom`, which is valid 1089 // for creating an exclusive reference to. 1090 unsafe { ptr.as_mut() } 1091 } 1092 }); 1093 } else { 1094 error = e.source_mut(); 1095 } 1096 } 1097 None 1098 } 1099 1100 /// Convert this error into a `Box<dyn core::error::Error>`. 1101 /// 1102 /// This is useful for integrating this crate's `Error`s into other 1103 /// universal-error libraries. 1104 /// 1105 /// This functionality is also available via a `From<Error> for Box<dyn 1106 /// core::error::Error + Send + Sync + 'static>>` implementation. 1107 /// 1108 /// # Example 1109 /// 1110 /// ``` 1111 /// # fn _foo() { 1112 /// #![cfg(feature = "std")] 1113 /// use std::fmt; 1114 /// 1115 /// /// A stub representing some other error library. 1116 /// #[derive(Debug)] 1117 /// pub struct OtherError { 1118 /// inner: Box<dyn std::error::Error + Send + Sync + 'static>, 1119 /// } 1120 /// 1121 /// impl fmt::Display for OtherError { 1122 /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1123 /// fmt::Display::fmt(&self.inner, f) 1124 /// } 1125 /// } 1126 /// 1127 /// impl std::error::Error for OtherError { 1128 /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 1129 /// self.inner.source() 1130 /// } 1131 /// } 1132 /// 1133 /// impl OtherError { 1134 /// /// Create an `OtherError` from another error. 1135 /// pub fn new<E>(error: E) -> Self 1136 /// where 1137 /// E: std::error::Error + Send + Sync + 'static, 1138 /// { 1139 /// OtherError { inner: Box::new(error) } 1140 /// } 1141 /// 1142 /// /// Create an `OtherError` from another, already-boxed error. 1143 /// pub fn from_boxed(error: Box<dyn std::error::Error + Send + Sync + 'static>) -> Self { 1144 /// OtherError { inner: error } 1145 /// } 1146 /// } 1147 /// 1148 /// # use wasmtime_internal_core::error as wasmtime; 1149 /// use wasmtime::Error; 1150 /// 1151 /// // Create an `Error`. 1152 /// let error = Error::msg("whoopsies"); 1153 /// 1154 /// // Convert it into an `OtherError`. 1155 /// let error = OtherError::from_boxed(error.into_boxed_dyn_error()); 1156 /// # } 1157 /// ``` 1158 #[inline] 1159 pub fn into_boxed_dyn_error(self) -> Box<dyn core::error::Error + Send + Sync + 'static> { 1160 /// A specialized OOM error that is zero-sized, so that it can always be 1161 /// boxed without allocation, and we can keep this method infallible (to 1162 /// match `anyhow`'s API). 1163 #[derive(Debug)] 1164 struct IntoBoxedDynCoreErrorFailure; 1165 1166 impl core::fmt::Display for IntoBoxedDynCoreErrorFailure { 1167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1168 write!( 1169 f, 1170 "failed to box error into `Box<dyn core::error::Error>` \ 1171 (allocation of {} bytes failed)", 1172 mem::size_of::<Error>() 1173 ) 1174 } 1175 } 1176 1177 impl core::error::Error for IntoBoxedDynCoreErrorFailure {} 1178 1179 match self.inner.into_boxed_dyn_core_error() { 1180 Ok(boxed) => boxed, 1181 Err(_oom) => { 1182 // NB: `Box::new` will never actually allocate for zero-sized types. 1183 Box::new(IntoBoxedDynCoreErrorFailure) as _ 1184 } 1185 } 1186 } 1187 } 1188 1189 /// `ErrorExt` wrapper for foreign `core::error::Error` implementations. 1190 /// 1191 /// For `Error::new`'s use only. 1192 /// 1193 /// NB: The `repr(transparent)` is required for safety of the `ErrorExt::ext_is` 1194 /// implementation and the casts that are performed using that method's return 1195 /// value. 1196 #[repr(transparent)] 1197 struct ForeignError<E>(E); 1198 1199 // Safety: `ext_is` is correct, `ext_move` always writes to `dest`. 1200 unsafe impl<E> ErrorExt for ForeignError<E> 1201 where 1202 E: core::error::Error + Send + Sync + 'static, 1203 { 1204 fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) { 1205 &self.0 1206 } 1207 1208 fn ext_into_boxed_dyn_core_error( 1209 self, 1210 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> { 1211 let boxed = try_new_uninit_box()?; 1212 Ok(Box::write(boxed, self.0) as _) 1213 } 1214 1215 fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> { 1216 None 1217 } 1218 1219 fn ext_source_mut(&mut self) -> Option<OomOrDynErrorMut<'_>> { 1220 None 1221 } 1222 1223 fn ext_take_source(&mut self) -> Option<OomOrDynError> { 1224 None 1225 } 1226 1227 unsafe fn ext_move(self, dest: NonNull<u8>) { 1228 // Safety: implied by this trait method's safety contract. 1229 unsafe { 1230 dest.cast::<E>().write(self.0); 1231 } 1232 } 1233 1234 fn ext_is(&self, type_id: TypeId) -> bool { 1235 // NB: need to check type id of `E`, not `Self` aka 1236 // `ForeignError<E>`. 1237 type_id == TypeId::of::<E>() 1238 } 1239 1240 #[cfg(feature = "backtrace")] 1241 fn take_backtrace(&mut self) -> Option<Backtrace> { 1242 None 1243 } 1244 } 1245 1246 /// `ErrorExt` wrapper for types given to `Error::msg`. 1247 /// 1248 /// For `Error::msg`'s use only. 1249 /// 1250 /// NB: The `repr(transparent)` is required for safety of the `ErrorExt::ext_is` 1251 /// implementation and the casts that are performed using that method's return 1252 /// value. 1253 #[repr(transparent)] 1254 struct MessageError<M>(M); 1255 1256 impl<M> fmt::Debug for MessageError<M> 1257 where 1258 M: fmt::Debug, 1259 { 1260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1261 self.0.fmt(f) 1262 } 1263 } 1264 1265 impl<M> fmt::Display for MessageError<M> 1266 where 1267 M: fmt::Display, 1268 { 1269 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1270 self.0.fmt(f) 1271 } 1272 } 1273 1274 impl<M> core::error::Error for MessageError<M> where M: fmt::Debug + fmt::Display {} 1275 1276 // Safety: `ext_is` is implemented correctly and `ext_move` always 1277 // writes to its pointer. 1278 unsafe impl<M> ErrorExt for MessageError<M> 1279 where 1280 M: fmt::Debug + fmt::Display + Send + Sync + 'static, 1281 { 1282 fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) { 1283 self 1284 } 1285 1286 fn ext_into_boxed_dyn_core_error( 1287 self, 1288 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> { 1289 let boxed = try_new_uninit_box()?; 1290 Ok(Box::write(boxed, self) as _) 1291 } 1292 1293 fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> { 1294 None 1295 } 1296 1297 fn ext_source_mut(&mut self) -> Option<OomOrDynErrorMut<'_>> { 1298 None 1299 } 1300 1301 fn ext_take_source(&mut self) -> Option<OomOrDynError> { 1302 None 1303 } 1304 1305 fn ext_is(&self, type_id: TypeId) -> bool { 1306 // NB: need to check type id of `M`, not `Self` aka 1307 // `MessageError<M>`. 1308 type_id == TypeId::of::<M>() 1309 } 1310 1311 unsafe fn ext_move(self, dest: NonNull<u8>) { 1312 // Safety: implied by this trait method's contract. 1313 unsafe { 1314 dest.cast::<M>().write(self.0); 1315 } 1316 } 1317 1318 #[cfg(feature = "backtrace")] 1319 fn take_backtrace(&mut self) -> Option<Backtrace> { 1320 None 1321 } 1322 } 1323 1324 /// `ErrorExt` wrapper for `Box<dyn core::error::Error>`. 1325 /// 1326 /// For `Error::from_boxed`'s use only. 1327 /// 1328 /// NB: The `repr(transparent)` is required for safety of the `ErrorExt::ext_is` 1329 /// implementation and the casts that are performed using that method's return 1330 /// value. 1331 #[repr(transparent)] 1332 struct BoxedError(Box<dyn core::error::Error + Send + Sync + 'static>); 1333 1334 // Safety: `ext_is` is implemented correctly and `ext_move` always 1335 // writes to its pointer. 1336 unsafe impl ErrorExt for BoxedError { 1337 fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) { 1338 &*self.0 1339 } 1340 1341 fn ext_into_boxed_dyn_core_error( 1342 self, 1343 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> { 1344 Ok(self.0) 1345 } 1346 1347 fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> { 1348 None 1349 } 1350 1351 fn ext_source_mut(&mut self) -> Option<OomOrDynErrorMut<'_>> { 1352 None 1353 } 1354 1355 fn ext_take_source(&mut self) -> Option<OomOrDynError> { 1356 None 1357 } 1358 1359 fn ext_is(&self, type_id: TypeId) -> bool { 1360 // NB: need to check type id of `BoxDynSendSyncError`, not 1361 // `BoxedError`. 1362 type_id == TypeId::of::<Box<dyn core::error::Error + Send + Sync + 'static>>() 1363 } 1364 1365 unsafe fn ext_move(self, dest: NonNull<u8>) { 1366 // Safety: implied by this trait method's contract. 1367 unsafe { 1368 dest.cast::<Box<dyn core::error::Error + Send + Sync + 'static>>() 1369 .write(self.0); 1370 } 1371 } 1372 1373 #[cfg(feature = "backtrace")] 1374 fn take_backtrace(&mut self) -> Option<Backtrace> { 1375 None 1376 } 1377 } 1378 1379 /// `ErrorExt` wrapper for `anyhow::Error`. 1380 /// 1381 /// For `Error::from_anyhow`'s use only. 1382 /// 1383 /// NB: The `repr(transparent)` is required for safety of the `ErrorExt::ext_is` 1384 /// implementation and the casts that are performed using that method's return 1385 /// value. 1386 #[repr(transparent)] 1387 #[cfg(feature = "anyhow")] 1388 struct AnyhowError(anyhow::Error); 1389 1390 // Safety: `ext_is` is implemented correctly and `ext_move` always 1391 // writes to its pointer. 1392 #[cfg(feature = "anyhow")] 1393 unsafe impl ErrorExt for AnyhowError { 1394 fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) { 1395 self.0.as_ref() 1396 } 1397 1398 fn ext_into_boxed_dyn_core_error( 1399 self, 1400 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> { 1401 Ok(self.0.into_boxed_dyn_error()) 1402 } 1403 1404 fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> { 1405 None 1406 } 1407 1408 fn ext_source_mut(&mut self) -> Option<OomOrDynErrorMut<'_>> { 1409 None 1410 } 1411 1412 fn ext_take_source(&mut self) -> Option<OomOrDynError> { 1413 None 1414 } 1415 1416 fn ext_is(&self, type_id: TypeId) -> bool { 1417 // NB: need to check type id of `BoxDynSendSyncError`, not 1418 // `AnyhowError`. 1419 type_id == TypeId::of::<anyhow::Error>() 1420 } 1421 1422 unsafe fn ext_move(self, dest: NonNull<u8>) { 1423 // Safety: implied by this trait method's contract. 1424 unsafe { 1425 dest.cast::<anyhow::Error>().write(self.0); 1426 } 1427 } 1428 1429 #[cfg(feature = "backtrace")] 1430 fn take_backtrace(&mut self) -> Option<Backtrace> { 1431 None 1432 } 1433 } 1434 1435 pub(crate) enum OomOrDynErrorRef<'a> { 1436 // Safety: this must always be a valid pointer to read a `DynError` from for 1437 // the `'a` lifetime. 1438 DynError(SharedPtr<'a, DynError>), 1439 1440 Oom(&'a OutOfMemory), 1441 } 1442 1443 impl<'a> Debug for OomOrDynErrorRef<'a> { 1444 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1445 self.debug(f) 1446 } 1447 } 1448 1449 impl<'a> OomOrDynErrorRef<'a> { 1450 fn display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1451 match self { 1452 OomOrDynErrorRef::DynError(e) => { 1453 // Safety: invariant of this type. 1454 let vtable = unsafe { e.as_ref().vtable }; 1455 // Safety: using the vtable associated with this pointer's 1456 // concrete type and the pointer is valid. 1457 unsafe { (vtable.display)(*e, f) } 1458 } 1459 OomOrDynErrorRef::Oom(oom) => fmt::Display::fmt(oom, f), 1460 } 1461 } 1462 1463 fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1464 match *self { 1465 OomOrDynErrorRef::Oom(oom) => f.debug_tuple("Oom").field(oom).finish(), 1466 OomOrDynErrorRef::DynError(error) => { 1467 struct DebugError<'a>(SharedPtr<'a, DynError>); 1468 impl fmt::Debug for DebugError<'_> { 1469 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1470 // Safety: invariant of `OomOrDynError` that the pointer 1471 // is valid. 1472 let vtable = unsafe { self.0.as_ref().vtable }; 1473 // Safety: the pointer is valid and the vtable is 1474 // associated with the pointer's concrete error type. 1475 unsafe { (vtable.debug)(self.0, f) } 1476 } 1477 } 1478 1479 let mut f = f.debug_struct("DynError"); 1480 f.field("error", &DebugError(error)); 1481 if let Some(source) = self.source() { 1482 f.field("source", &source); 1483 } 1484 f.finish() 1485 } 1486 } 1487 } 1488 1489 fn source(&self) -> Option<OomOrDynErrorRef<'a>> { 1490 match self { 1491 OomOrDynErrorRef::DynError(e) => { 1492 // Safety: invariant of this type. 1493 let vtable = unsafe { e.as_ref().vtable }; 1494 // Safety: using the vtable associated with this pointer's 1495 // concrete type and the pointer is valid. 1496 unsafe { (vtable.source)(*e) } 1497 } 1498 OomOrDynErrorRef::Oom(_) => None, 1499 } 1500 } 1501 1502 fn is<E>(&self) -> bool 1503 where 1504 E: fmt::Display + fmt::Debug + Send + Sync + 'static, 1505 { 1506 match self { 1507 OomOrDynErrorRef::DynError(e) => { 1508 // Safety: invariant of this type. 1509 let vtable = unsafe { e.as_ref().vtable }; 1510 // Safety: using the vtable associated with this pointer's 1511 // concrete type and the pointer is valid. 1512 unsafe { (vtable.is)(*e, TypeId::of::<E>()) } 1513 } 1514 OomOrDynErrorRef::Oom(_) => TypeId::of::<E>() == TypeId::of::<OutOfMemory>(), 1515 } 1516 } 1517 1518 pub(crate) fn as_dyn_core_error(&self) -> &'a (dyn core::error::Error + Send + Sync + 'static) { 1519 match *self { 1520 OomOrDynErrorRef::DynError(e) => { 1521 // Safety: invariant of this type. 1522 let vtable = unsafe { e.as_ref().vtable }; 1523 // Safety: using the vtable associated with this pointer's 1524 // concrete type and the pointer is valid. 1525 unsafe { (vtable.as_dyn_core_error)(e) } 1526 } 1527 OomOrDynErrorRef::Oom(oom) => oom as _, 1528 } 1529 } 1530 1531 #[cfg(feature = "backtrace")] 1532 fn backtrace(&self) -> &'a Backtrace { 1533 match self { 1534 OomOrDynErrorRef::DynError(e) => { 1535 // Safety: invariant of this type. 1536 let r = unsafe { e.as_ref() }; 1537 r.backtrace 1538 .as_ref() 1539 .expect("the first error in the chain always has the backtrace") 1540 } 1541 1542 OomOrDynErrorRef::Oom(_) => { 1543 static DISABLED: Backtrace = Backtrace::disabled(); 1544 &DISABLED 1545 } 1546 } 1547 } 1548 } 1549 1550 pub(crate) enum OomOrDynErrorMut<'a> { 1551 // Safety: this must always be a valid pointer to read and write a 1552 // `DynError` from for the `'a` lifetime. 1553 DynError(MutPtr<'a, DynError>), 1554 1555 Oom(&'a mut OutOfMemory), 1556 } 1557 1558 impl<'a> OomOrDynErrorMut<'a> { 1559 fn as_ref(&self) -> OomOrDynErrorRef<'_> { 1560 match self { 1561 OomOrDynErrorMut::DynError(e) => OomOrDynErrorRef::DynError(e.as_shared_ptr()), 1562 OomOrDynErrorMut::Oom(oom) => OomOrDynErrorRef::Oom(oom), 1563 } 1564 } 1565 1566 fn source_mut(&mut self) -> Option<OomOrDynErrorMut<'a>> { 1567 match self { 1568 OomOrDynErrorMut::DynError(e) => { 1569 // Safety: invariant of this type. 1570 let vtable = unsafe { e.as_ref().vtable }; 1571 // Safety: using the vtable associated with this pointer's 1572 // concrete type and the pointer is valid. 1573 unsafe { (vtable.source_mut)(e.raw_copy()) } 1574 } 1575 OomOrDynErrorMut::Oom(_) => None, 1576 } 1577 } 1578 } 1579 1580 /// Bit packed version of `enum { BoxedDynError, OutOfMemory }` that relies on 1581 /// implicit pointer tagging and `OutOfMemory` being zero-sized. 1582 #[repr(transparent)] 1583 pub(crate) struct OomOrDynError { 1584 // Safety: this must always be the casted-to-`u8` version of either (a) 1585 // `0x1`, or (b) a valid, owned `DynError` pointer. (Note that these cases 1586 // cannot overlap because `DynError`'s alignment is greater than `0x1`.) 1587 inner: NonNull<u8>, 1588 } 1589 1590 // Safety: `OomOrDynError` is either an `OutOfMemory` or a `BoxedDynError` and 1591 // both are `Send`. 1592 unsafe impl Send for OomOrDynError {} 1593 1594 // Safety: `OomOrDynError` is either an `OutOfMemory` or a `BoxedDynError` and 1595 // both are `Sync`. 1596 unsafe impl Sync for OomOrDynError {} 1597 1598 const _OOM_OR_DYN_ERROR_SEND_SYNC_SAFETY: () = { 1599 const fn assert_send_sync<T: Send + Sync>() {} 1600 assert_send_sync::<OutOfMemory>(); 1601 assert_send_sync::<BoxedDynError>(); 1602 }; 1603 1604 impl Drop for OomOrDynError { 1605 fn drop(&mut self) { 1606 if self.is_boxed_dyn_error() { 1607 let inner = self.inner.cast::<DynError>(); 1608 let inner = OwnedPtr::new(inner); 1609 // Safety: the pointer is a valid `DynError` pointer. 1610 let _ = unsafe { BoxedDynError::from_owned_ptr(inner) }; 1611 } else { 1612 debug_assert!(self.is_oom()); 1613 } 1614 } 1615 } 1616 1617 impl From<BoxedDynError> for OomOrDynError { 1618 fn from(boxed: BoxedDynError) -> Self { 1619 let inner = boxed.into_owned_ptr().into_non_null().cast::<u8>(); 1620 debug_assert!(!Self::is_oom_ptr(inner)); 1621 OomOrDynError { inner } 1622 } 1623 } 1624 1625 impl OomOrDynError { 1626 const _SIZE: () = assert!(mem::size_of::<OomOrDynError>() == mem::size_of::<usize>()); 1627 1628 /// Our pointer tagging relies on this property, which implies that 1629 /// `Self::OOM_BIT` is never set for any `*mut DynError` pointer. 1630 const _DYN_ERROR_HAS_GREATER_ALIGN_THAN_OOM: () = assert!(mem::align_of::<DynError>() > 1); 1631 1632 /// If this bit is set in the inner pointer's address, then it is a bitpacked 1633 /// `OutOfMemory` rather than a pointer to a boxed dyn error. 1634 const OOM_BIT: usize = 0x1; 1635 1636 pub(crate) const fn new_oom_ptr(size: usize) -> NonNull<u8> { 1637 let size = if size > (isize::MAX as usize) { 1638 isize::MAX as usize 1639 } else { 1640 size 1641 }; 1642 let repr = (size << 1) | Self::OOM_BIT; 1643 let inner = core::ptr::without_provenance_mut(repr); 1644 NonNull::new(inner).unwrap() 1645 } 1646 1647 pub(crate) fn new_oom(bitpacked: NonNull<u8>) -> Self { 1648 assert!(Self::is_oom_ptr(bitpacked)); 1649 OomOrDynError { inner: bitpacked } 1650 } 1651 1652 fn is_oom_ptr(ptr: NonNull<u8>) -> bool { 1653 (ptr.addr().get() & Self::OOM_BIT) == Self::OOM_BIT 1654 } 1655 1656 fn is_oom(&self) -> bool { 1657 Self::is_oom_ptr(self.inner) 1658 } 1659 1660 fn is_boxed_dyn_error(&self) -> bool { 1661 !self.is_oom() 1662 } 1663 1664 pub(crate) fn oom_size(inner: NonNull<u8>) -> usize { 1665 debug_assert!(Self::is_oom_ptr(inner)); 1666 inner.addr().get() >> 1 1667 } 1668 1669 /// # Safety 1670 /// 1671 /// `self.is_oom()` must be true. 1672 unsafe fn unchecked_oom(&self) -> &OutOfMemory { 1673 debug_assert!(self.is_oom()); 1674 // Safety: `self.is_oom()` and `OutOfMemory` has the same representation 1675 // as `Self`. 1676 unsafe { mem::transmute(self) } 1677 } 1678 1679 /// # Safety 1680 /// 1681 /// `self.is_oom()` must be true. 1682 unsafe fn unchecked_oom_mut(&mut self) -> &mut OutOfMemory { 1683 debug_assert!(self.is_oom()); 1684 // Safety: `self.is_oom()` and `OutOfMemory` has the same representation 1685 // as `Self`. 1686 unsafe { mem::transmute(self) } 1687 } 1688 1689 /// # Safety 1690 /// 1691 /// `self.is_boxed_dyn_error()` must be true. 1692 unsafe fn unchecked_into_dyn_error(self) -> OwnedPtr<DynError> { 1693 debug_assert!(self.is_boxed_dyn_error()); 1694 let inner = self.inner.cast::<DynError>(); 1695 mem::forget(self); 1696 OwnedPtr::new(inner) 1697 } 1698 1699 /// # Safety 1700 /// 1701 /// `self.is_boxed_dyn_error()` must be true. 1702 unsafe fn unchecked_dyn_error_ref(&self) -> SharedPtr<'_, DynError> { 1703 debug_assert!(self.is_boxed_dyn_error()); 1704 SharedPtr::new(self.inner.cast::<DynError>()) 1705 } 1706 1707 /// # Safety 1708 /// 1709 /// `self.is_boxed_dyn_error()` must be true. 1710 unsafe fn unchecked_dyn_error_mut(&mut self) -> MutPtr<'_, DynError> { 1711 debug_assert!(self.is_boxed_dyn_error()); 1712 MutPtr::new(self.inner.cast::<DynError>()) 1713 } 1714 1715 pub(crate) fn unpack(&self) -> OomOrDynErrorRef<'_> { 1716 if self.is_oom() { 1717 // Safety: is_oom() is true. 1718 OomOrDynErrorRef::Oom(unsafe { self.unchecked_oom() }) 1719 } else { 1720 debug_assert!(self.is_boxed_dyn_error()); 1721 // Safety: self.is_boxed_dyn_error() is true. 1722 OomOrDynErrorRef::DynError(unsafe { self.unchecked_dyn_error_ref() }) 1723 } 1724 } 1725 1726 pub(crate) fn unpack_mut(&mut self) -> OomOrDynErrorMut<'_> { 1727 if self.is_oom() { 1728 // Safety: self.is_oom() is true 1729 OomOrDynErrorMut::Oom(unsafe { self.unchecked_oom_mut() }) 1730 } else { 1731 debug_assert!(self.is_boxed_dyn_error()); 1732 // Safety: self.is_boxed_dyn_error() is true. 1733 OomOrDynErrorMut::DynError(unsafe { self.unchecked_dyn_error_mut() }) 1734 } 1735 } 1736 1737 pub(crate) fn into_boxed_dyn_core_error( 1738 self, 1739 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> { 1740 if self.is_oom() { 1741 let boxed = try_new_uninit_box::<OutOfMemory>()?; 1742 // Safety: `self.is_oom()` is true. 1743 let boxed = Box::write(boxed, unsafe { *self.unchecked_oom() }); 1744 Ok(boxed as _) 1745 } else { 1746 debug_assert!(self.is_boxed_dyn_error()); 1747 // Safety: this is a boxed dyn error. 1748 let ptr = unsafe { self.unchecked_into_dyn_error() }; 1749 // Safety: invariant of the type that the pointer is valid. 1750 let vtable = unsafe { ptr.as_ref().vtable }; 1751 // Safety: the pointer is valid and the vtable is associated with 1752 // this pointer's concrete error type. 1753 unsafe { (vtable.into_boxed_dyn_core_error)(ptr) } 1754 } 1755 } 1756 1757 /// Given that this is known to be an instance of the type associated with 1758 /// the given `TypeId`, do an owning-downcast to that type, writing the 1759 /// result through the given `ret_ptr`, and deallocating `self` along the 1760 /// way. 1761 /// 1762 /// The `ret_ptr`'s storage will contain an initialized instance of the 1763 /// associated type upon this method's successful return. 1764 /// 1765 /// # Safety 1766 /// 1767 /// This error (or another in its chain) must be of the type associated with 1768 /// `TypeId`. 1769 /// 1770 /// The given `ret_ptr` must point to a valid-but-uninitialized storage 1771 /// location for an instance of the type associated with the given `TypeId`. 1772 pub(crate) unsafe fn downcast(self, type_id: TypeId, ret_ptr: NonNull<u8>) { 1773 if self.is_oom() { 1774 debug_assert_eq!(type_id, TypeId::of::<OutOfMemory>()); 1775 // Safety: this is an OOM error. 1776 let oom = unsafe { self.unchecked_oom() }; 1777 // Safety: implied by this method's safety contract. 1778 unsafe { 1779 ret_ptr.cast::<OutOfMemory>().write(*oom); 1780 } 1781 } else { 1782 debug_assert!(self.is_boxed_dyn_error()); 1783 // Safety: this is a boxed dyn error. 1784 let ptr = unsafe { self.unchecked_into_dyn_error() }; 1785 // Safety: invariant of this type that the pointer is valid. 1786 let vtable = unsafe { ptr.as_ref().vtable }; 1787 // Safety: the pointer is valid and the vtable is associated with 1788 // this pointer's concrete type. 1789 unsafe { (vtable.downcast)(ptr, type_id, ret_ptr) } 1790 } 1791 } 1792 } 1793 1794 /// An iterator over each error in an [`Error`]'s context chain. 1795 /// 1796 /// The iterator yields `&'a (dyn core::error::Error + 'static)` items. 1797 /// 1798 /// Iterates from the most recently added error context towards the root cause. 1799 /// 1800 /// Created by the [`Error::chain`] method. See that method's documentation for 1801 /// more details. 1802 pub struct Chain<'a> { 1803 state: ChainState<'a>, 1804 } 1805 1806 enum ChainState<'a> { 1807 Ours(OomOrDynErrorRef<'a>), 1808 Core(Option<&'a (dyn core::error::Error + 'static)>), 1809 } 1810 1811 impl<'a> Chain<'a> { 1812 fn new(error: OomOrDynErrorRef<'a>) -> Self { 1813 Self { 1814 state: ChainState::Ours(error), 1815 } 1816 } 1817 } 1818 1819 impl<'a> Iterator for Chain<'a> { 1820 type Item = &'a (dyn core::error::Error + 'static); 1821 1822 #[inline] 1823 fn next(&mut self) -> Option<Self::Item> { 1824 match &mut self.state { 1825 ChainState::Ours(e) => { 1826 let core = e.as_dyn_core_error(); 1827 self.state = if let Some(e) = e.source() { 1828 ChainState::Ours(e) 1829 } else { 1830 ChainState::Core(core.source()) 1831 }; 1832 Some(core) 1833 } 1834 ChainState::Core(error) => { 1835 let e = error.take()?; 1836 self.state = ChainState::Core(e.source()); 1837 Some(e) 1838 } 1839 } 1840 } 1841 } 1842 1843 impl FusedIterator for Chain<'_> {} 1844 1845 #[cfg(test)] 1846 mod tests { 1847 use super::*; 1848 1849 #[derive(Debug)] 1850 struct TestError; 1851 1852 impl fmt::Display for TestError { 1853 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1854 fmt::Debug::fmt(self, f) 1855 } 1856 } 1857 1858 impl core::error::Error for TestError {} 1859 1860 #[test] 1861 fn from_oom() { 1862 let mut error = Error::from(OutOfMemory::new(5)); 1863 assert!(error.is::<OutOfMemory>()); 1864 assert!(error.downcast_ref::<OutOfMemory>().is_some()); 1865 assert!(error.downcast_mut::<OutOfMemory>().is_some()); 1866 1867 // NB: use this module's scope to check that the inner representation is 1868 // `OomOrDynError::Oom` and not a `Box<OutOfMemory> as Box<dyn 1869 // Error>`. This is why this test cannot be in `tests/tests.rs`. 1870 assert!(error.inner.is_oom()); 1871 } 1872 1873 #[test] 1874 fn dyn_error_and_concrete_error_layouts_are_compatible() { 1875 type Concrete = ConcreteError<TestError>; 1876 1877 let dyn_size = mem::size_of::<DynError>(); 1878 let concrete_size = mem::size_of::<Concrete>(); 1879 assert!( 1880 dyn_size <= concrete_size, 1881 "assertion failed: {dyn_size} <= {concrete_size}" 1882 ); 1883 1884 let dyn_align = mem::align_of::<DynError>(); 1885 let concrete_align = mem::align_of::<Concrete>(); 1886 assert!( 1887 dyn_align <= concrete_align, 1888 "assertion failed: {dyn_align} <= {concrete_align}" 1889 ); 1890 1891 let dyn_offset = mem::offset_of!(DynError, vtable); 1892 let concrete_offset = mem::offset_of!(Concrete, vtable); 1893 assert_eq!(dyn_offset, concrete_offset); 1894 1895 #[cfg(feature = "backtrace")] 1896 { 1897 let dyn_offset = mem::offset_of!(DynError, backtrace); 1898 let concrete_offset = mem::offset_of!(Concrete, backtrace); 1899 assert_eq!(dyn_offset, concrete_offset); 1900 } 1901 } 1902 } 1903