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`][crate::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>()`][crate::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>()`][crate::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>()`][crate::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>()`][crate::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>()`][crate::OutOfMemory] is true. 717 /// 718 /// # Example 719 /// 720 /// ``` 721 /// # use wasmtime_internal_core::error as wasmtime; 722 /// use wasmtime::Error; 723 /// 724 /// let error = Error::msg("root cause"); 725 /// let error = error.context("failed to bonkinate"); 726 /// let error = error.context("cannot frob the blobbins"); 727 /// 728 /// assert!( 729 /// format!("{error:?}").contains( 730 /// r#" 731 /// cannot frob the blobbins 732 /// 733 /// Caused by: 734 /// 0: failed to bonkinate 735 /// 1: root cause 736 /// "#.trim(), 737 /// ), 738 /// ); 739 /// ``` 740 pub fn context<C>(self, context: C) -> Self 741 where 742 C: fmt::Display + Send + Sync + 'static, 743 { 744 if self.inner.is_oom() { 745 self 746 } else { 747 Self::from_error_ext(ContextError { 748 context, 749 error: Some(self), 750 }) 751 } 752 } 753 754 #[inline] 755 pub(crate) fn from_error_ext(error: impl ErrorExt) -> Self { 756 match BoxedDynError::new(error) { 757 Ok(boxed) => Error { 758 inner: boxed.into(), 759 }, 760 Err(oom) => Error { inner: oom.into() }, 761 } 762 } 763 764 /// Get this error's backtrace. 765 /// 766 /// Backtraces will be automatically captured on initial `Error` creation 767 /// when all of the following conditions are met: 768 /// 769 /// * This crate's `"backtrace"` cargo feature is enabled 770 /// * Rust's `std::backtrace::Backtrace` supports the platform 771 /// * The `RUST_BACKTRACE` or `RUST_LIB_BACKTRACE` environment variables 772 /// are set and non-zero 773 /// 774 /// See [the `std::backtrace::Backtrace` 775 /// documentation](https://doc.rust-lang.org/stable/std/backtrace/struct.Backtrace.html) 776 /// for more details on backtraces. 777 /// 778 /// Note that `std::backtrace::Backtrace` does not provide a 779 /// fallible-capture mechanism that returns an error, rather than aborting 780 /// the process, when it encounters memory exhaustion. If you require 781 /// out-of-memory error handling, do not enable this crate's `"backtrace"` 782 /// cargo feature. 783 /// 784 /// # Example 785 /// 786 /// ``` 787 /// # fn _foo() { 788 /// #![cfg(feature = "backtrace")] 789 /// # use wasmtime_internal_core::error as wasmtime; 790 /// use std::backtrace::BacktraceStatus; 791 /// use wasmtime::Error; 792 /// 793 /// let error = Error::msg("whoops"); 794 /// 795 /// let backtrace = error.backtrace(); 796 /// if let BacktraceStatus::Captured = backtrace.status() { 797 /// println!("error backtrace is:\n{backtrace}"); 798 /// } 799 /// # } 800 /// ``` 801 #[inline] 802 #[cfg(feature = "backtrace")] 803 pub fn backtrace(&self) -> &Backtrace { 804 self.inner.unpack().backtrace() 805 } 806 807 /// Iterate over this error's context chain. 808 /// 809 /// The iterator yields `&(dyn core::error::Error + 'static)` items. 810 /// 811 /// Iterates from the most recently added error context towards the root 812 /// cause. 813 /// 814 /// # Example 815 /// 816 /// ``` 817 /// # use wasmtime_internal_core::error as wasmtime; 818 /// use wasmtime::Error; 819 /// 820 /// let error = Error::msg("root cause"); 821 /// let error = error.context("failed to reticulate splines"); 822 /// let error = error.context("aborting launch"); 823 /// 824 /// let messages: Vec<_> = error.chain().map(|e| e.to_string()).collect(); 825 /// assert_eq!( 826 /// messages, 827 /// ["aborting launch", "failed to reticulate splines", "root cause"], 828 /// ); 829 /// ``` 830 #[inline] 831 pub fn chain(&self) -> Chain<'_> { 832 Chain::new(self.inner.unpack()) 833 } 834 835 /// Get the last error in the context chain. 836 /// 837 /// # Example 838 /// 839 /// ``` 840 /// # use wasmtime_internal_core::error as wasmtime; 841 /// use wasmtime::Error; 842 /// 843 /// let error = Error::msg("ghosts"); 844 /// let error = error.context("failed to reticulate splines"); 845 /// let error = error.context("aborting launch"); 846 /// 847 /// assert_eq!( 848 /// error.root_cause().to_string(), 849 /// "ghosts", 850 /// ); 851 /// ``` 852 #[inline] 853 pub fn root_cause(&self) -> &(dyn core::error::Error + 'static) { 854 self.chain().last().expect("chain is always non-empty") 855 } 856 857 /// Is this an `E` error? 858 /// 859 /// Returns true if any error in the context chain is an `E`. 860 /// 861 /// # Example 862 /// 863 /// ``` 864 /// # use wasmtime_internal_core as wasmtime; 865 /// use wasmtime::error::{Error, OutOfMemory}; 866 /// 867 /// let oom = Error::from(OutOfMemory::new(1234)); 868 /// assert!(oom.is::<OutOfMemory>()); 869 /// assert!(!oom.is::<std::num::TryFromIntError>()); 870 /// 871 /// // Here is an example with additional error context. 872 /// let error = Error::from(u8::try_from(u32::MAX).unwrap_err()); 873 /// let error = error.context(format!("cannot convert {} into a u8", u32::MAX)); 874 /// assert!( 875 /// error.is::<std::num::TryFromIntError>(), 876 /// "root cause is an int conversion failure", 877 /// ); 878 /// assert!( 879 /// error.is::<String>(), 880 /// "additional context is a `String`", 881 /// ); 882 /// assert!( 883 /// !error.is::<OutOfMemory>(), 884 /// "no error in the chain is an out-of-memory error", 885 /// ); 886 /// ``` 887 pub fn is<E>(&self) -> bool 888 where 889 E: fmt::Display + fmt::Debug + Send + Sync + 'static, 890 { 891 let mut error = Some(self.inner.unpack()); 892 while let Some(e) = error { 893 if e.is::<E>() { 894 return true; 895 } else { 896 error = e.source(); 897 } 898 } 899 false 900 } 901 902 /// Downcast this error into an `E`, taking ownership. 903 /// 904 /// If this error is an `E`, then `Ok(E)` is returned. Otherwise, 905 /// `Err(self)` is returned. 906 /// 907 /// If there are multiple instances of `E` in this error's chain, then the 908 /// first (as encountered by [`Error::chain`]'s iteration order) is 909 /// returned. 910 /// 911 /// # Example 912 /// 913 /// ``` 914 /// # use wasmtime_internal_core as wasmtime; 915 /// use wasmtime::error::{Error, OutOfMemory}; 916 /// 917 /// let error = Error::msg("whoops"); 918 /// 919 /// // `error` is not an `OutOfMemory`. 920 /// let downcasted = error.downcast::<OutOfMemory>(); 921 /// assert!(downcasted.is_err()); 922 /// 923 /// // Get the original `error` back. 924 /// let error = downcasted.unwrap_err(); 925 /// 926 /// // `error` is an `&str`. 927 /// let downcasted = error.downcast::<&str>(); 928 /// assert!(downcasted.is_ok()); 929 /// assert_eq!(downcasted.unwrap(), "whoops"); 930 /// 931 /// // If there are multiple `E`s in the chain, the first in the chain is 932 /// // returned. 933 /// let error = Error::msg("root cause"); 934 /// let error = error.context("failed to recombobulate"); 935 /// assert_eq!( 936 /// error.downcast::<&str>().unwrap(), 937 /// "failed to recombobulate", 938 /// ); 939 /// ``` 940 pub fn downcast<E>(self) -> Result<E, Self> 941 where 942 E: fmt::Display + fmt::Debug + Send + Sync + 'static, 943 { 944 if !self.is::<E>() { 945 return Err(self); 946 } 947 948 let mut value = mem::MaybeUninit::<E>::uninit(); 949 950 // Safety: this error is an `E` and the given pointer is valid to write 951 // an `E` to. 952 unsafe { 953 self.inner 954 .downcast(TypeId::of::<E>(), NonNull::from(&mut value).cast::<u8>()); 955 } 956 957 // Safety: `OomOrDynError::downcast` guarantees that the given pointer's 958 // data is initialized upon successful return. 959 Ok(unsafe { value.assume_init() }) 960 } 961 962 /// Downcast this error into a shared `&E` borrow. 963 /// 964 /// If this error is an `E`, then `Some(&E)` is returned. Otherwise, `None` 965 /// is returned. 966 /// 967 /// If there are multiple instances of `E` in this error's chain, then the 968 /// first (as encountered by [`Error::chain`]'s iteration order) is 969 /// returned. 970 /// 971 /// # Example 972 /// 973 /// ``` 974 /// # use wasmtime_internal_core as wasmtime; 975 /// use wasmtime::error::{Error, OutOfMemory}; 976 /// 977 /// let error = Error::msg("whoops"); 978 /// 979 /// // `error` is not an `OutOfMemory`. 980 /// assert!(error.downcast_ref::<OutOfMemory>().is_none()); 981 /// 982 /// // `error` is an `&str`. 983 /// assert!(error.downcast_ref::<&str>().is_some()); 984 /// assert_eq!(*error.downcast_ref::<&str>().unwrap(), "whoops"); 985 /// 986 /// // If there are multiple `E`s in the chain, the first in the chain is 987 /// // returned. 988 /// let error = Error::msg("root cause"); 989 /// let error = error.context("failed to recombobulate"); 990 /// assert_eq!( 991 /// *error.downcast_ref::<&str>().unwrap(), 992 /// "failed to recombobulate", 993 /// ); 994 /// ``` 995 pub fn downcast_ref<E>(&self) -> Option<&E> 996 where 997 E: fmt::Display + fmt::Debug + Send + Sync + 'static, 998 { 999 let mut error = Some(self.inner.unpack()); 1000 while let Some(e) = error { 1001 if e.is::<E>() { 1002 return Some(match e { 1003 OomOrDynErrorRef::DynError(ptr) => { 1004 let ptr = ptr.cast::<ConcreteError<E>>(); 1005 // Safety: we own the pointer, it is valid for reading, 1006 // and we checked that it is an `E`. 1007 let r = unsafe { ptr.as_ref() }; 1008 &r.error 1009 } 1010 OomOrDynErrorRef::Oom(oom) => { 1011 // Note: Even though we know that `E == OutOfMemory` 1012 // here, we still have to do this dance to satisfy the 1013 // type system. 1014 debug_assert_eq!(TypeId::of::<E>(), TypeId::of::<OutOfMemory>()); 1015 let ptr = NonNull::from(oom); 1016 let ptr = ptr.cast::<E>(); 1017 // Safety: the pointer points to `oom`, which is valid 1018 // for creating a shared reference to. 1019 unsafe { ptr.as_ref() } 1020 } 1021 }); 1022 } else { 1023 error = e.source(); 1024 } 1025 } 1026 None 1027 } 1028 1029 /// Downcast this error into an exclusive `&mut E` borrow. 1030 /// 1031 /// If this error is an `E`, then `Some(&mut E)` is returned. Otherwise, 1032 /// `None` is returned. 1033 /// 1034 /// If there are multiple instances of `E` in this error's chain, then the 1035 /// first (as encountered by [`Error::chain`]'s iteration order) is 1036 /// returned. 1037 /// 1038 /// # Example 1039 /// 1040 /// ``` 1041 /// # use wasmtime_internal_core as wasmtime; 1042 /// use wasmtime::error::{Error, OutOfMemory}; 1043 /// 1044 /// let mut error = Error::msg("whoops"); 1045 /// 1046 /// // `error` is not an `OutOfMemory`. 1047 /// assert!(error.downcast_mut::<OutOfMemory>().is_none()); 1048 /// 1049 /// // `error` is an `&str`. 1050 /// assert!(error.downcast_mut::<&str>().is_some()); 1051 /// assert_eq!(*error.downcast_mut::<&str>().unwrap(), "whoops"); 1052 /// *error.downcast_mut::<&str>().unwrap() = "yikes"; 1053 /// assert_eq!(*error.downcast_mut::<&str>().unwrap(), "yikes"); 1054 /// 1055 /// // If there are multiple `E`s in the chain, the first in the chain is 1056 /// // returned. 1057 /// let error = Error::msg("root cause"); 1058 /// let mut error = error.context("failed to recombobulate"); 1059 /// assert_eq!( 1060 /// *error.downcast_mut::<&str>().unwrap(), 1061 /// "failed to recombobulate", 1062 /// ); 1063 /// ``` 1064 pub fn downcast_mut<E>(&mut self) -> Option<&mut E> 1065 where 1066 E: fmt::Display + fmt::Debug + Send + Sync + 'static, 1067 { 1068 let mut error = Some(self.inner.unpack_mut()); 1069 while let Some(mut e) = error.take() { 1070 if e.as_ref().is::<E>() { 1071 return Some(match e { 1072 OomOrDynErrorMut::DynError(ptr) => { 1073 let mut ptr = ptr.cast::<ConcreteError<E>>(); 1074 // Safety: we own the pointer, it is valid for reading 1075 // and writing, and we checked that it is an `E`. 1076 let r = unsafe { ptr.as_mut() }; 1077 &mut r.error 1078 } 1079 OomOrDynErrorMut::Oom(oom) => { 1080 // Note: Even though we know that `E == OutOfMemory` 1081 // here, we still have to do this dance to satisfy the 1082 // type system. 1083 debug_assert_eq!(TypeId::of::<E>(), TypeId::of::<OutOfMemory>()); 1084 let ptr = NonNull::from(oom); 1085 let mut ptr = ptr.cast::<E>(); 1086 // Safety: the pointer points to `oom`, which is valid 1087 // for creating an exclusive reference to. 1088 unsafe { ptr.as_mut() } 1089 } 1090 }); 1091 } else { 1092 error = e.source_mut(); 1093 } 1094 } 1095 None 1096 } 1097 1098 /// Convert this error into a `Box<dyn core::error::Error>`. 1099 /// 1100 /// This is useful for integrating this crate's `Error`s into other 1101 /// universal-error libraries. 1102 /// 1103 /// This functionality is also available via a `From<Error> for Box<dyn 1104 /// core::error::Error + Send + Sync + 'static>>` implementation. 1105 /// 1106 /// # Example 1107 /// 1108 /// ``` 1109 /// # fn _foo() { 1110 /// #![cfg(feature = "std")] 1111 /// use std::fmt; 1112 /// 1113 /// /// A stub representing some other error library. 1114 /// #[derive(Debug)] 1115 /// pub struct OtherError { 1116 /// inner: Box<dyn std::error::Error + Send + Sync + 'static>, 1117 /// } 1118 /// 1119 /// impl fmt::Display for OtherError { 1120 /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1121 /// fmt::Display::fmt(&self.inner, f) 1122 /// } 1123 /// } 1124 /// 1125 /// impl std::error::Error for OtherError { 1126 /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 1127 /// self.inner.source() 1128 /// } 1129 /// } 1130 /// 1131 /// impl OtherError { 1132 /// /// Create an `OtherError` from another error. 1133 /// pub fn new<E>(error: E) -> Self 1134 /// where 1135 /// E: std::error::Error + Send + Sync + 'static, 1136 /// { 1137 /// OtherError { inner: Box::new(error) } 1138 /// } 1139 /// 1140 /// /// Create an `OtherError` from another, already-boxed error. 1141 /// pub fn from_boxed(error: Box<dyn std::error::Error + Send + Sync + 'static>) -> Self { 1142 /// OtherError { inner: error } 1143 /// } 1144 /// } 1145 /// 1146 /// # use wasmtime_internal_core::error as wasmtime; 1147 /// use wasmtime::Error; 1148 /// 1149 /// // Create an `Error`. 1150 /// let error = Error::msg("whoopsies"); 1151 /// 1152 /// // Convert it into an `OtherError`. 1153 /// let error = OtherError::from_boxed(error.into_boxed_dyn_error()); 1154 /// # } 1155 /// ``` 1156 #[inline] 1157 pub fn into_boxed_dyn_error(self) -> Box<dyn core::error::Error + Send + Sync + 'static> { 1158 /// A specialized OOM error that is zero-sized, so that it can always be 1159 /// boxed without allocation, and we can keep this method infallible (to 1160 /// match `anyhow`'s API). 1161 #[derive(Debug)] 1162 struct IntoBoxedDynCoreErrorFailure; 1163 1164 impl core::fmt::Display for IntoBoxedDynCoreErrorFailure { 1165 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1166 write!( 1167 f, 1168 "failed to box error into `Box<dyn core::error::Error>` \ 1169 (allocation of {} bytes failed)", 1170 mem::size_of::<Error>() 1171 ) 1172 } 1173 } 1174 1175 impl core::error::Error for IntoBoxedDynCoreErrorFailure {} 1176 1177 match self.inner.into_boxed_dyn_core_error() { 1178 Ok(boxed) => boxed, 1179 Err(_oom) => { 1180 // NB: `Box::new` will never actually allocate for zero-sized types. 1181 Box::new(IntoBoxedDynCoreErrorFailure) as _ 1182 } 1183 } 1184 } 1185 } 1186 1187 /// `ErrorExt` wrapper for foreign `core::error::Error` implementations. 1188 /// 1189 /// For `Error::new`'s use only. 1190 /// 1191 /// NB: The `repr(transparent)` is required for safety of the `ErrorExt::ext_is` 1192 /// implementation and the casts that are performed using that method's return 1193 /// value. 1194 #[repr(transparent)] 1195 struct ForeignError<E>(E); 1196 1197 // Safety: `ext_is` is correct, `ext_move` always writes to `dest`. 1198 unsafe impl<E> ErrorExt for ForeignError<E> 1199 where 1200 E: core::error::Error + Send + Sync + 'static, 1201 { 1202 fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) { 1203 &self.0 1204 } 1205 1206 fn ext_into_boxed_dyn_core_error( 1207 self, 1208 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> { 1209 let boxed = try_new_uninit_box()?; 1210 Ok(Box::write(boxed, self.0) as _) 1211 } 1212 1213 fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> { 1214 None 1215 } 1216 1217 fn ext_source_mut(&mut self) -> Option<OomOrDynErrorMut<'_>> { 1218 None 1219 } 1220 1221 fn ext_take_source(&mut self) -> Option<OomOrDynError> { 1222 None 1223 } 1224 1225 unsafe fn ext_move(self, dest: NonNull<u8>) { 1226 // Safety: implied by this trait method's safety contract. 1227 unsafe { 1228 dest.cast::<E>().write(self.0); 1229 } 1230 } 1231 1232 fn ext_is(&self, type_id: TypeId) -> bool { 1233 // NB: need to check type id of `E`, not `Self` aka 1234 // `ForeignError<E>`. 1235 type_id == TypeId::of::<E>() 1236 } 1237 1238 #[cfg(feature = "backtrace")] 1239 fn take_backtrace(&mut self) -> Option<Backtrace> { 1240 None 1241 } 1242 } 1243 1244 /// `ErrorExt` wrapper for types given to `Error::msg`. 1245 /// 1246 /// For `Error::msg`'s use only. 1247 /// 1248 /// NB: The `repr(transparent)` is required for safety of the `ErrorExt::ext_is` 1249 /// implementation and the casts that are performed using that method's return 1250 /// value. 1251 #[repr(transparent)] 1252 struct MessageError<M>(M); 1253 1254 impl<M> fmt::Debug for MessageError<M> 1255 where 1256 M: fmt::Debug, 1257 { 1258 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1259 self.0.fmt(f) 1260 } 1261 } 1262 1263 impl<M> fmt::Display for MessageError<M> 1264 where 1265 M: fmt::Display, 1266 { 1267 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1268 self.0.fmt(f) 1269 } 1270 } 1271 1272 impl<M> core::error::Error for MessageError<M> where M: fmt::Debug + fmt::Display {} 1273 1274 // Safety: `ext_is` is implemented correctly and `ext_move` always 1275 // writes to its pointer. 1276 unsafe impl<M> ErrorExt for MessageError<M> 1277 where 1278 M: fmt::Debug + fmt::Display + Send + Sync + 'static, 1279 { 1280 fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) { 1281 self 1282 } 1283 1284 fn ext_into_boxed_dyn_core_error( 1285 self, 1286 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> { 1287 let boxed = try_new_uninit_box()?; 1288 Ok(Box::write(boxed, self) as _) 1289 } 1290 1291 fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> { 1292 None 1293 } 1294 1295 fn ext_source_mut(&mut self) -> Option<OomOrDynErrorMut<'_>> { 1296 None 1297 } 1298 1299 fn ext_take_source(&mut self) -> Option<OomOrDynError> { 1300 None 1301 } 1302 1303 fn ext_is(&self, type_id: TypeId) -> bool { 1304 // NB: need to check type id of `M`, not `Self` aka 1305 // `MessageError<M>`. 1306 type_id == TypeId::of::<M>() 1307 } 1308 1309 unsafe fn ext_move(self, dest: NonNull<u8>) { 1310 // Safety: implied by this trait method's contract. 1311 unsafe { 1312 dest.cast::<M>().write(self.0); 1313 } 1314 } 1315 1316 #[cfg(feature = "backtrace")] 1317 fn take_backtrace(&mut self) -> Option<Backtrace> { 1318 None 1319 } 1320 } 1321 1322 /// `ErrorExt` wrapper for `Box<dyn core::error::Error>`. 1323 /// 1324 /// For `Error::from_boxed`'s use only. 1325 /// 1326 /// NB: The `repr(transparent)` is required for safety of the `ErrorExt::ext_is` 1327 /// implementation and the casts that are performed using that method's return 1328 /// value. 1329 #[repr(transparent)] 1330 struct BoxedError(Box<dyn core::error::Error + Send + Sync + 'static>); 1331 1332 // Safety: `ext_is` is implemented correctly and `ext_move` always 1333 // writes to its pointer. 1334 unsafe impl ErrorExt for BoxedError { 1335 fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) { 1336 &*self.0 1337 } 1338 1339 fn ext_into_boxed_dyn_core_error( 1340 self, 1341 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> { 1342 Ok(self.0) 1343 } 1344 1345 fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> { 1346 None 1347 } 1348 1349 fn ext_source_mut(&mut self) -> Option<OomOrDynErrorMut<'_>> { 1350 None 1351 } 1352 1353 fn ext_take_source(&mut self) -> Option<OomOrDynError> { 1354 None 1355 } 1356 1357 fn ext_is(&self, type_id: TypeId) -> bool { 1358 // NB: need to check type id of `BoxDynSendSyncError`, not 1359 // `BoxedError`. 1360 type_id == TypeId::of::<Box<dyn core::error::Error + Send + Sync + 'static>>() 1361 } 1362 1363 unsafe fn ext_move(self, dest: NonNull<u8>) { 1364 // Safety: implied by this trait method's contract. 1365 unsafe { 1366 dest.cast::<Box<dyn core::error::Error + Send + Sync + 'static>>() 1367 .write(self.0); 1368 } 1369 } 1370 1371 #[cfg(feature = "backtrace")] 1372 fn take_backtrace(&mut self) -> Option<Backtrace> { 1373 None 1374 } 1375 } 1376 1377 /// `ErrorExt` wrapper for `anyhow::Error`. 1378 /// 1379 /// For `Error::from_anyhow`'s use only. 1380 /// 1381 /// NB: The `repr(transparent)` is required for safety of the `ErrorExt::ext_is` 1382 /// implementation and the casts that are performed using that method's return 1383 /// value. 1384 #[repr(transparent)] 1385 #[cfg(feature = "anyhow")] 1386 struct AnyhowError(anyhow::Error); 1387 1388 // Safety: `ext_is` is implemented correctly and `ext_move` always 1389 // writes to its pointer. 1390 #[cfg(feature = "anyhow")] 1391 unsafe impl ErrorExt for AnyhowError { 1392 fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) { 1393 self.0.as_ref() 1394 } 1395 1396 fn ext_into_boxed_dyn_core_error( 1397 self, 1398 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> { 1399 Ok(self.0.into_boxed_dyn_error()) 1400 } 1401 1402 fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> { 1403 None 1404 } 1405 1406 fn ext_source_mut(&mut self) -> Option<OomOrDynErrorMut<'_>> { 1407 None 1408 } 1409 1410 fn ext_take_source(&mut self) -> Option<OomOrDynError> { 1411 None 1412 } 1413 1414 fn ext_is(&self, type_id: TypeId) -> bool { 1415 // NB: need to check type id of `BoxDynSendSyncError`, not 1416 // `AnyhowError`. 1417 type_id == TypeId::of::<anyhow::Error>() 1418 } 1419 1420 unsafe fn ext_move(self, dest: NonNull<u8>) { 1421 // Safety: implied by this trait method's contract. 1422 unsafe { 1423 dest.cast::<anyhow::Error>().write(self.0); 1424 } 1425 } 1426 1427 #[cfg(feature = "backtrace")] 1428 fn take_backtrace(&mut self) -> Option<Backtrace> { 1429 None 1430 } 1431 } 1432 1433 pub(crate) enum OomOrDynErrorRef<'a> { 1434 // Safety: this must always be a valid pointer to read a `DynError` from for 1435 // the `'a` lifetime. 1436 DynError(SharedPtr<'a, DynError>), 1437 1438 Oom(&'a OutOfMemory), 1439 } 1440 1441 impl<'a> Debug for OomOrDynErrorRef<'a> { 1442 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1443 self.debug(f) 1444 } 1445 } 1446 1447 impl<'a> OomOrDynErrorRef<'a> { 1448 fn display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1449 match self { 1450 OomOrDynErrorRef::DynError(e) => { 1451 // Safety: invariant of this type. 1452 let vtable = unsafe { e.as_ref().vtable }; 1453 // Safety: using the vtable associated with this pointer's 1454 // concrete type and the pointer is valid. 1455 unsafe { (vtable.display)(*e, f) } 1456 } 1457 OomOrDynErrorRef::Oom(oom) => fmt::Display::fmt(oom, f), 1458 } 1459 } 1460 1461 fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1462 match *self { 1463 OomOrDynErrorRef::Oom(oom) => f.debug_tuple("Oom").field(oom).finish(), 1464 OomOrDynErrorRef::DynError(error) => { 1465 struct DebugError<'a>(SharedPtr<'a, DynError>); 1466 impl fmt::Debug for DebugError<'_> { 1467 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1468 // Safety: invariant of `OomOrDynError` that the pointer 1469 // is valid. 1470 let vtable = unsafe { self.0.as_ref().vtable }; 1471 // Safety: the pointer is valid and the vtable is 1472 // associated with the pointer's concrete error type. 1473 unsafe { (vtable.debug)(self.0, f) } 1474 } 1475 } 1476 1477 let mut f = f.debug_struct("DynError"); 1478 f.field("error", &DebugError(error)); 1479 if let Some(source) = self.source() { 1480 f.field("source", &source); 1481 } 1482 f.finish() 1483 } 1484 } 1485 } 1486 1487 fn source(&self) -> Option<OomOrDynErrorRef<'a>> { 1488 match self { 1489 OomOrDynErrorRef::DynError(e) => { 1490 // Safety: invariant of this type. 1491 let vtable = unsafe { e.as_ref().vtable }; 1492 // Safety: using the vtable associated with this pointer's 1493 // concrete type and the pointer is valid. 1494 unsafe { (vtable.source)(*e) } 1495 } 1496 OomOrDynErrorRef::Oom(_) => None, 1497 } 1498 } 1499 1500 fn is<E>(&self) -> bool 1501 where 1502 E: fmt::Display + fmt::Debug + Send + Sync + 'static, 1503 { 1504 match self { 1505 OomOrDynErrorRef::DynError(e) => { 1506 // Safety: invariant of this type. 1507 let vtable = unsafe { e.as_ref().vtable }; 1508 // Safety: using the vtable associated with this pointer's 1509 // concrete type and the pointer is valid. 1510 unsafe { (vtable.is)(*e, TypeId::of::<E>()) } 1511 } 1512 OomOrDynErrorRef::Oom(_) => TypeId::of::<E>() == TypeId::of::<OutOfMemory>(), 1513 } 1514 } 1515 1516 pub(crate) fn as_dyn_core_error(&self) -> &'a (dyn core::error::Error + Send + Sync + 'static) { 1517 match *self { 1518 OomOrDynErrorRef::DynError(e) => { 1519 // Safety: invariant of this type. 1520 let vtable = unsafe { e.as_ref().vtable }; 1521 // Safety: using the vtable associated with this pointer's 1522 // concrete type and the pointer is valid. 1523 unsafe { (vtable.as_dyn_core_error)(e) } 1524 } 1525 OomOrDynErrorRef::Oom(oom) => oom as _, 1526 } 1527 } 1528 1529 #[cfg(feature = "backtrace")] 1530 fn backtrace(&self) -> &'a Backtrace { 1531 match self { 1532 OomOrDynErrorRef::DynError(e) => { 1533 // Safety: invariant of this type. 1534 let r = unsafe { e.as_ref() }; 1535 r.backtrace 1536 .as_ref() 1537 .expect("the first error in the chain always has the backtrace") 1538 } 1539 1540 OomOrDynErrorRef::Oom(_) => { 1541 static DISABLED: Backtrace = Backtrace::disabled(); 1542 &DISABLED 1543 } 1544 } 1545 } 1546 } 1547 1548 pub(crate) enum OomOrDynErrorMut<'a> { 1549 // Safety: this must always be a valid pointer to read and write a 1550 // `DynError` from for the `'a` lifetime. 1551 DynError(MutPtr<'a, DynError>), 1552 1553 Oom(&'a mut OutOfMemory), 1554 } 1555 1556 impl<'a> OomOrDynErrorMut<'a> { 1557 fn as_ref(&self) -> OomOrDynErrorRef<'_> { 1558 match self { 1559 OomOrDynErrorMut::DynError(e) => OomOrDynErrorRef::DynError(e.as_shared_ptr()), 1560 OomOrDynErrorMut::Oom(oom) => OomOrDynErrorRef::Oom(oom), 1561 } 1562 } 1563 1564 fn source_mut(&mut self) -> Option<OomOrDynErrorMut<'a>> { 1565 match self { 1566 OomOrDynErrorMut::DynError(e) => { 1567 // Safety: invariant of this type. 1568 let vtable = unsafe { e.as_ref().vtable }; 1569 // Safety: using the vtable associated with this pointer's 1570 // concrete type and the pointer is valid. 1571 unsafe { (vtable.source_mut)(e.raw_copy()) } 1572 } 1573 OomOrDynErrorMut::Oom(_) => None, 1574 } 1575 } 1576 } 1577 1578 /// Bit packed version of `enum { BoxedDynError, OutOfMemory }` that relies on 1579 /// implicit pointer tagging and `OutOfMemory` being zero-sized. 1580 #[repr(transparent)] 1581 pub(crate) struct OomOrDynError { 1582 // Safety: this must always be the casted-to-`u8` version of either (a) 1583 // `0x1`, or (b) a valid, owned `DynError` pointer. (Note that these cases 1584 // cannot overlap because `DynError`'s alignment is greater than `0x1`.) 1585 inner: NonNull<u8>, 1586 } 1587 1588 // Safety: `OomOrDynError` is either an `OutOfMemory` or a `BoxedDynError` and 1589 // both are `Send`. 1590 unsafe impl Send for OomOrDynError {} 1591 1592 // Safety: `OomOrDynError` is either an `OutOfMemory` or a `BoxedDynError` and 1593 // both are `Sync`. 1594 unsafe impl Sync for OomOrDynError {} 1595 1596 const _OOM_OR_DYN_ERROR_SEND_SYNC_SAFETY: () = { 1597 const fn assert_send_sync<T: Send + Sync>() {} 1598 assert_send_sync::<OutOfMemory>(); 1599 assert_send_sync::<BoxedDynError>(); 1600 }; 1601 1602 impl Drop for OomOrDynError { 1603 fn drop(&mut self) { 1604 if self.is_boxed_dyn_error() { 1605 let inner = self.inner.cast::<DynError>(); 1606 let inner = OwnedPtr::new(inner); 1607 // Safety: the pointer is a valid `DynError` pointer. 1608 let _ = unsafe { BoxedDynError::from_owned_ptr(inner) }; 1609 } else { 1610 debug_assert!(self.is_oom()); 1611 } 1612 } 1613 } 1614 1615 impl From<BoxedDynError> for OomOrDynError { 1616 fn from(boxed: BoxedDynError) -> Self { 1617 let inner = boxed.into_owned_ptr().into_non_null().cast::<u8>(); 1618 debug_assert!(!Self::is_oom_ptr(inner)); 1619 OomOrDynError { inner } 1620 } 1621 } 1622 1623 impl OomOrDynError { 1624 const _SIZE: () = assert!(mem::size_of::<OomOrDynError>() == mem::size_of::<usize>()); 1625 1626 /// Our pointer tagging relies on this property, which implies that 1627 /// `Self::OOM_BIT` is never set for any `*mut DynError` pointer. 1628 const _DYN_ERROR_HAS_GREATER_ALIGN_THAN_OOM: () = assert!(mem::align_of::<DynError>() > 1); 1629 1630 /// If this bit is set in the inner pointer's address, then it is a bitpacked 1631 /// `OutOfMemory` rather than a pointer to a boxed dyn error. 1632 const OOM_BIT: usize = 0x1; 1633 1634 pub(crate) const fn new_oom_ptr(size: usize) -> NonNull<u8> { 1635 let size = if size > (isize::MAX as usize) { 1636 isize::MAX as usize 1637 } else { 1638 size 1639 }; 1640 let repr = (size << 1) | Self::OOM_BIT; 1641 let inner = core::ptr::without_provenance_mut(repr); 1642 NonNull::new(inner).unwrap() 1643 } 1644 1645 pub(crate) fn new_oom(bitpacked: NonNull<u8>) -> Self { 1646 assert!(Self::is_oom_ptr(bitpacked)); 1647 OomOrDynError { inner: bitpacked } 1648 } 1649 1650 fn is_oom_ptr(ptr: NonNull<u8>) -> bool { 1651 (ptr.addr().get() & Self::OOM_BIT) == Self::OOM_BIT 1652 } 1653 1654 fn is_oom(&self) -> bool { 1655 Self::is_oom_ptr(self.inner) 1656 } 1657 1658 fn is_boxed_dyn_error(&self) -> bool { 1659 !self.is_oom() 1660 } 1661 1662 pub(crate) fn oom_size(inner: NonNull<u8>) -> usize { 1663 debug_assert!(Self::is_oom_ptr(inner)); 1664 inner.addr().get() >> 1 1665 } 1666 1667 /// # Safety 1668 /// 1669 /// `self.is_oom()` must be true. 1670 unsafe fn unchecked_oom(&self) -> &OutOfMemory { 1671 debug_assert!(self.is_oom()); 1672 // Safety: `self.is_oom()` and `OutOfMemory` has the same representation 1673 // as `Self`. 1674 unsafe { mem::transmute(self) } 1675 } 1676 1677 /// # Safety 1678 /// 1679 /// `self.is_oom()` must be true. 1680 unsafe fn unchecked_oom_mut(&mut self) -> &mut OutOfMemory { 1681 debug_assert!(self.is_oom()); 1682 // Safety: `self.is_oom()` and `OutOfMemory` has the same representation 1683 // as `Self`. 1684 unsafe { mem::transmute(self) } 1685 } 1686 1687 /// # Safety 1688 /// 1689 /// `self.is_boxed_dyn_error()` must be true. 1690 unsafe fn unchecked_into_dyn_error(self) -> OwnedPtr<DynError> { 1691 debug_assert!(self.is_boxed_dyn_error()); 1692 let inner = self.inner.cast::<DynError>(); 1693 mem::forget(self); 1694 OwnedPtr::new(inner) 1695 } 1696 1697 /// # Safety 1698 /// 1699 /// `self.is_boxed_dyn_error()` must be true. 1700 unsafe fn unchecked_dyn_error_ref(&self) -> SharedPtr<'_, DynError> { 1701 debug_assert!(self.is_boxed_dyn_error()); 1702 SharedPtr::new(self.inner.cast::<DynError>()) 1703 } 1704 1705 /// # Safety 1706 /// 1707 /// `self.is_boxed_dyn_error()` must be true. 1708 unsafe fn unchecked_dyn_error_mut(&mut self) -> MutPtr<'_, DynError> { 1709 debug_assert!(self.is_boxed_dyn_error()); 1710 MutPtr::new(self.inner.cast::<DynError>()) 1711 } 1712 1713 pub(crate) fn unpack(&self) -> OomOrDynErrorRef<'_> { 1714 if self.is_oom() { 1715 // Safety: is_oom() is true. 1716 OomOrDynErrorRef::Oom(unsafe { self.unchecked_oom() }) 1717 } else { 1718 debug_assert!(self.is_boxed_dyn_error()); 1719 // Safety: self.is_boxed_dyn_error() is true. 1720 OomOrDynErrorRef::DynError(unsafe { self.unchecked_dyn_error_ref() }) 1721 } 1722 } 1723 1724 pub(crate) fn unpack_mut(&mut self) -> OomOrDynErrorMut<'_> { 1725 if self.is_oom() { 1726 // Safety: self.is_oom() is true 1727 OomOrDynErrorMut::Oom(unsafe { self.unchecked_oom_mut() }) 1728 } else { 1729 debug_assert!(self.is_boxed_dyn_error()); 1730 // Safety: self.is_boxed_dyn_error() is true. 1731 OomOrDynErrorMut::DynError(unsafe { self.unchecked_dyn_error_mut() }) 1732 } 1733 } 1734 1735 pub(crate) fn into_boxed_dyn_core_error( 1736 self, 1737 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> { 1738 if self.is_oom() { 1739 let boxed = try_new_uninit_box::<OutOfMemory>()?; 1740 // Safety: `self.is_oom()` is true. 1741 let boxed = Box::write(boxed, unsafe { *self.unchecked_oom() }); 1742 Ok(boxed as _) 1743 } else { 1744 debug_assert!(self.is_boxed_dyn_error()); 1745 // Safety: this is a boxed dyn error. 1746 let ptr = unsafe { self.unchecked_into_dyn_error() }; 1747 // Safety: invariant of the type that the pointer is valid. 1748 let vtable = unsafe { ptr.as_ref().vtable }; 1749 // Safety: the pointer is valid and the vtable is associated with 1750 // this pointer's concrete error type. 1751 unsafe { (vtable.into_boxed_dyn_core_error)(ptr) } 1752 } 1753 } 1754 1755 /// Given that this is known to be an instance of the type associated with 1756 /// the given `TypeId`, do an owning-downcast to that type, writing the 1757 /// result through the given `ret_ptr`, and deallocating `self` along the 1758 /// way. 1759 /// 1760 /// The `ret_ptr`'s storage will contain an initialized instance of the 1761 /// associated type upon this method's successful return. 1762 /// 1763 /// # Safety 1764 /// 1765 /// This error (or another in its chain) must be of the type associated with 1766 /// `TypeId`. 1767 /// 1768 /// The given `ret_ptr` must point to a valid-but-uninitialized storage 1769 /// location for an instance of the type associated with the given `TypeId`. 1770 pub(crate) unsafe fn downcast(self, type_id: TypeId, ret_ptr: NonNull<u8>) { 1771 if self.is_oom() { 1772 debug_assert_eq!(type_id, TypeId::of::<OutOfMemory>()); 1773 // Safety: this is an OOM error. 1774 let oom = unsafe { self.unchecked_oom() }; 1775 // Safety: implied by this method's safety contract. 1776 unsafe { 1777 ret_ptr.cast::<OutOfMemory>().write(*oom); 1778 } 1779 } else { 1780 debug_assert!(self.is_boxed_dyn_error()); 1781 // Safety: this is a boxed dyn error. 1782 let ptr = unsafe { self.unchecked_into_dyn_error() }; 1783 // Safety: invariant of this type that the pointer is valid. 1784 let vtable = unsafe { ptr.as_ref().vtable }; 1785 // Safety: the pointer is valid and the vtable is associated with 1786 // this pointer's concrete type. 1787 unsafe { (vtable.downcast)(ptr, type_id, ret_ptr) } 1788 } 1789 } 1790 } 1791 1792 /// An iterator over each error in an [`Error`]'s context chain. 1793 /// 1794 /// The iterator yields `&'a (dyn core::error::Error + 'static)` items. 1795 /// 1796 /// Iterates from the most recently added error context towards the root cause. 1797 /// 1798 /// Created by the [`Error::chain`] method. See that method's documentation for 1799 /// more details. 1800 pub struct Chain<'a> { 1801 state: ChainState<'a>, 1802 } 1803 1804 enum ChainState<'a> { 1805 Ours(OomOrDynErrorRef<'a>), 1806 Core(Option<&'a (dyn core::error::Error + 'static)>), 1807 } 1808 1809 impl<'a> Chain<'a> { 1810 fn new(error: OomOrDynErrorRef<'a>) -> Self { 1811 Self { 1812 state: ChainState::Ours(error), 1813 } 1814 } 1815 } 1816 1817 impl<'a> Iterator for Chain<'a> { 1818 type Item = &'a (dyn core::error::Error + 'static); 1819 1820 #[inline] 1821 fn next(&mut self) -> Option<Self::Item> { 1822 match &mut self.state { 1823 ChainState::Ours(e) => { 1824 let core = e.as_dyn_core_error(); 1825 self.state = if let Some(e) = e.source() { 1826 ChainState::Ours(e) 1827 } else { 1828 ChainState::Core(core.source()) 1829 }; 1830 Some(core) 1831 } 1832 ChainState::Core(error) => { 1833 let e = error.take()?; 1834 self.state = ChainState::Core(e.source()); 1835 Some(e) 1836 } 1837 } 1838 } 1839 } 1840 1841 impl FusedIterator for Chain<'_> {} 1842 1843 #[cfg(test)] 1844 mod tests { 1845 use super::*; 1846 1847 #[derive(Debug)] 1848 struct TestError; 1849 1850 impl fmt::Display for TestError { 1851 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 1852 fmt::Debug::fmt(self, f) 1853 } 1854 } 1855 1856 impl core::error::Error for TestError {} 1857 1858 #[test] 1859 fn from_oom() { 1860 let mut error = Error::from(OutOfMemory::new(5)); 1861 assert!(error.is::<OutOfMemory>()); 1862 assert!(error.downcast_ref::<OutOfMemory>().is_some()); 1863 assert!(error.downcast_mut::<OutOfMemory>().is_some()); 1864 1865 // NB: use this module's scope to check that the inner representation is 1866 // `OomOrDynError::Oom` and not a `Box<OutOfMemory> as Box<dyn 1867 // Error>`. This is why this test cannot be in `tests/tests.rs`. 1868 assert!(error.inner.is_oom()); 1869 } 1870 1871 #[test] 1872 fn dyn_error_and_concrete_error_layouts_are_compatible() { 1873 type Concrete = ConcreteError<TestError>; 1874 1875 let dyn_size = mem::size_of::<DynError>(); 1876 let concrete_size = mem::size_of::<Concrete>(); 1877 assert!( 1878 dyn_size <= concrete_size, 1879 "assertion failed: {dyn_size} <= {concrete_size}" 1880 ); 1881 1882 let dyn_align = mem::align_of::<DynError>(); 1883 let concrete_align = mem::align_of::<Concrete>(); 1884 assert!( 1885 dyn_align <= concrete_align, 1886 "assertion failed: {dyn_align} <= {concrete_align}" 1887 ); 1888 1889 let dyn_offset = mem::offset_of!(DynError, vtable); 1890 let concrete_offset = mem::offset_of!(Concrete, vtable); 1891 assert_eq!(dyn_offset, concrete_offset); 1892 1893 #[cfg(feature = "backtrace")] 1894 { 1895 let dyn_offset = mem::offset_of!(DynError, backtrace); 1896 let concrete_offset = mem::offset_of!(Concrete, backtrace); 1897 assert_eq!(dyn_offset, concrete_offset); 1898 } 1899 } 1900 } 1901