wasmtime_internal_error/error.rs
1use super::boxed::try_new_uninit_box;
2use super::context::ContextError;
3use super::ptr::{MutPtr, OwnedPtr, SharedPtr};
4use super::vtable::Vtable;
5use crate::{OutOfMemory, Result};
6use alloc::boxed::Box;
7use core::{
8 any::TypeId,
9 fmt::{self, Debug},
10 iter::FusedIterator,
11 mem,
12 ptr::NonNull,
13};
14#[cfg(feature = "backtrace")]
15use std::backtrace::{Backtrace, BacktraceStatus};
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.
25pub(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)]
82pub(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)]
97pub(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
106pub(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`.
112unsafe impl Send for BoxedDynError {}
113
114// Safety: `BoxedDynError::new` ensures that every concrete error type we make a
115// `BoxedDynError` from is `Sync`.
116unsafe impl Sync for BoxedDynError {}
117
118impl 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
133impl 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::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_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/// [`anyhow!`][crate::anyhow] macro is preferred:
264///
265/// ```
266/// # use wasmtime_internal_error as wasmtime;
267/// use wasmtime::{anyhow, Error};
268///
269/// let x = 42;
270/// let my_error: Error = anyhow!("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_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_error as wasmtime;
318/// use wasmtime::{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_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_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)]
424pub 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.
431const _ERROR_IS_ONE_WORD_LARGE: () = assert!(mem::size_of::<Error>() == mem::size_of::<usize>());
432const _RESULT_OF_UNIT_IS_ONE_WORD_LARGE: () =
433 assert!(mem::size_of::<Result<()>>() == mem::size_of::<usize>());
434
435impl 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 for (i, e) in Chain::new(source).enumerate() {
450 writeln!(f, "\t{i}: {e}")?;
451 }
452 }
453
454 #[cfg(feature = "backtrace")]
455 {
456 let backtrace = inner.backtrace();
457 if let BacktraceStatus::Captured = backtrace.status() {
458 f.write_str("\nStack backtrace:\n")?;
459 fmt::Display::fmt(backtrace, f)?;
460 }
461 }
462
463 Ok(())
464 }
465}
466
467impl fmt::Display for Error {
468 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469 let inner = self.inner.unpack();
470 inner.display(f)?;
471
472 if f.alternate() {
473 if let Some(e) = inner.source() {
474 for e in Chain::new(e) {
475 write!(f, ": {e}")?;
476 }
477 }
478 }
479
480 Ok(())
481 }
482}
483
484impl<E> From<E> for Error
485where
486 E: core::error::Error + Send + Sync + 'static,
487{
488 fn from(error: E) -> Self {
489 Self::new(error)
490 }
491}
492
493impl From<Error> for Box<dyn core::error::Error + Send + Sync + 'static> {
494 #[inline]
495 fn from(error: Error) -> Self {
496 error.into_boxed_dyn_error()
497 }
498}
499
500impl From<Error> for Box<dyn core::error::Error + Send + 'static> {
501 #[inline]
502 fn from(error: Error) -> Self {
503 error.into_boxed_dyn_error()
504 }
505}
506
507impl From<Error> for Box<dyn core::error::Error + 'static> {
508 #[inline]
509 fn from(error: Error) -> Self {
510 error.into_boxed_dyn_error()
511 }
512}
513
514/// Convert a [`Error`] into an [`anyhow::Error`].
515///
516/// # Example
517///
518/// ```
519/// # use wasmtime_internal_error as wasmtime;
520/// let wasmtime_error = wasmtime::Error::msg("whoops");
521/// let anyhow_error = anyhow::Error::from(wasmtime_error);
522/// ```
523//
524// Unfortunately, we can't also implement `From<anyhow::Error> for Error`
525// because of trait coherence. From Rust's trait system's point of view,
526// `anyhow` could theoretically add an `core::error::Error for anyhow::Error`
527// implementation, which would make our desired `From<anyhow::Error>`
528// implementation conflict with our existing `From<E: core::error::Error>`
529// implementation. They cannot in fact add that implementation, however, because
530// they already have a `From<E: core::error::Error> for anyhow::Error`
531// implementation and so adding `core::error::Error for anyhow::Error` would
532// cause that impl to conflict with `From<T> for T` (which is the same reason we
533// cannot implement `core::error::Error for Error`). Nonetheless, our hands are
534// tied here.
535#[cfg(feature = "anyhow")]
536impl From<Error> for anyhow::Error {
537 #[inline]
538 fn from(e: Error) -> Self {
539 anyhow::Error::from_boxed(e.into_boxed_dyn_error())
540 }
541}
542
543impl core::ops::Deref for Error {
544 type Target = dyn core::error::Error + Send + Sync + 'static;
545
546 fn deref(&self) -> &Self::Target {
547 self.as_ref()
548 }
549}
550
551impl AsRef<dyn core::error::Error> for Error {
552 #[inline]
553 fn as_ref(&self) -> &(dyn core::error::Error + 'static) {
554 self.inner.unpack().as_dyn_core_error()
555 }
556}
557
558impl AsRef<dyn core::error::Error + Send + Sync> for Error {
559 #[inline]
560 fn as_ref(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
561 self.inner.unpack().as_dyn_core_error()
562 }
563}
564
565impl Error {
566 /// Construct a new `Error` from a type that implements
567 /// `core::error::Error`.
568 ///
569 /// Calling [`error.is::<E>()`][Error::is] will return `true` for the new
570 /// error (unless there was a memory allocation failure).
571 ///
572 /// This boxes the inner error, but if that box allocation fails, then this
573 /// function returns an `Error` where
574 /// [`error.is::<OutOfMemory>()`][crate::OutOfMemory] is true.
575 ///
576 /// # Example
577 ///
578 /// ```
579 /// # use wasmtime_internal_error as wasmtime;
580 /// use wasmtime::Error;
581 ///
582 /// let error = Error::new(std::fmt::Error);
583 /// ```
584 pub fn new<E>(error: E) -> Self
585 where
586 E: core::error::Error + Send + Sync + 'static,
587 {
588 if TypeId::of::<E>() == TypeId::of::<OutOfMemory>() {
589 return Error {
590 inner: OutOfMemory::new().into(),
591 };
592 }
593
594 Self::from_error_ext(ForeignError(error))
595 }
596
597 /// Construct a new `Error` from any type that implements `Debug` and
598 /// `Display`.
599 ///
600 /// Calling [`error.is::<M>()`][Error::is] will return `true` for the new
601 /// error (unless there was a memory allocation failure).
602 ///
603 /// This boxes the inner `M` type, but if that box allocation fails, then
604 /// this function returns an `Error` where
605 /// [`error.is::<OutOfMemory>()`][crate::OutOfMemory] is true.
606 ///
607 /// # Example
608 ///
609 /// ```
610 /// # use wasmtime_internal_error as wasmtime;
611 /// use wasmtime::Error;
612 ///
613 /// let error = Error::msg("hello");
614 /// ```
615 pub fn msg<M>(message: M) -> Self
616 where
617 M: fmt::Debug + fmt::Display + Send + Sync + 'static,
618 {
619 Self::from_error_ext(MessageError(message))
620 }
621
622 /// Create an `Error` from a `Box<dyn core::error::Error>`.
623 ///
624 /// This is useful when converting errors from other universal-error
625 /// libraries into this crate's `Error` type. Prefer [`Error::from_anyhow`]
626 /// for converting `anyhow::Error`s into `Error`s, as that preserves
627 /// `error.is::<anyhow::Error>()`.
628 ///
629 /// Calling [`error.is::<Box<dyn core::error::Error + Send + Sync +
630 /// 'static>>()`][Error::is] will return `true` for the new error (unless
631 /// there was a memory allocation failure).
632 ///
633 /// This reboxes the inner error, but if that box allocation fails, then
634 /// this function returns an `Error` where
635 /// [`error.is::<OutOfMemory>()`][crate::OutOfMemory] is true.
636 ///
637 /// # Example
638 ///
639 /// ```
640 /// # fn _foo() {
641 /// #![cfg(all(feature = "std", feature = "anyhow"))]
642 /// # use wasmtime_internal_error as wasmtime;
643 /// use std::error::Error;
644 ///
645 /// let anyhow_error = anyhow::Error::msg("whoops");
646 /// let boxed_error: Box<dyn Error + Send + Sync + 'static> = anyhow_error.into_boxed_dyn_error();
647 /// let wasmtime_error = wasmtime::Error::from_boxed(boxed_error);
648 /// # }
649 /// ```
650 pub fn from_boxed(error: Box<dyn core::error::Error + Send + Sync + 'static>) -> Self {
651 Self::from_error_ext(BoxedError(error))
652 }
653
654 /// Convert an `anyhow::Error` into an `Error`.
655 ///
656 /// Calling [`error.is::<anyhow::Error>()`][Error::is] will return `true`
657 /// for the new error (unless there was a memory allocation failure).
658 ///
659 /// This reboxes the `anyhow::Error`, but if that box allocation fails, then
660 /// this function returns an `Error` where
661 /// [`error.is::<OutOfMemory>()`][crate::OutOfMemory] is true.
662 ///
663 /// # Example
664 ///
665 /// ```
666 /// # fn _foo() {
667 /// #![cfg(all(feature = "std", feature = "anyhow"))]
668 /// # use wasmtime_internal_error as wasmtime;
669 /// let anyhow_error = anyhow::Error::msg("failed to flim the flam");
670 /// let wasmtime_error = wasmtime::Error::from_anyhow(anyhow_error);
671 /// assert_eq!(
672 /// wasmtime_error.to_string(),
673 /// "failed to flim the flam",
674 /// );
675 /// # }
676 /// ```
677 #[cfg(feature = "anyhow")]
678 #[inline]
679 pub fn from_anyhow(error: anyhow::Error) -> Self {
680 Self::from_error_ext(AnyhowError(error))
681 }
682
683 /// Add additional context to this error.
684 ///
685 /// The new context will show up first in the error chain, and the original
686 /// error will come next.
687 ///
688 /// This is similar to the [`Context::context`] trait method, but because it
689 /// is a method directly on [`Error`], there is no need for lazily-computing
690 /// the error context (like `with_context` does).
691 ///
692 /// Calling [`error.is::<C>()`][Error::is] will return `true` for the new
693 /// error (unless there was a memory allocation failure) in addition to any
694 /// other types `T` for which it was already the case that
695 /// `error.is::<T>()`.
696 ///
697 /// This boxes the inner `C` type, but if that box allocation fails, then
698 /// this function returns an `Error` where
699 /// [`error.is::<OutOfMemory>()`][crate::OutOfMemory] is true.
700 ///
701 /// # Example
702 ///
703 /// ```
704 /// # use wasmtime_internal_error as wasmtime;
705 /// use wasmtime::Error;
706 ///
707 /// let error = Error::msg("root cause");
708 /// let error = error.context("failed to bonkinate");
709 /// let error = error.context("cannot frob the blobbins");
710 ///
711 /// assert!(
712 /// format!("{error:?}").contains(
713 /// r#"
714 /// cannot frob the blobbins
715 ///
716 /// Caused by:
717 /// 0: failed to bonkinate
718 /// 1: root cause
719 /// "#.trim(),
720 /// ),
721 /// );
722 /// ```
723 pub fn context<C>(self, context: C) -> Self
724 where
725 C: fmt::Display + Send + Sync + 'static,
726 {
727 if self.inner.is_oom() {
728 self
729 } else {
730 Self::from_error_ext(ContextError {
731 context,
732 error: Some(self),
733 })
734 }
735 }
736
737 #[inline]
738 pub(crate) fn from_error_ext(error: impl ErrorExt) -> Self {
739 match BoxedDynError::new(error) {
740 Ok(boxed) => Error {
741 inner: boxed.into(),
742 },
743 Err(oom) => out_of_line_slow_path!(Error { inner: oom.into() }),
744 }
745 }
746
747 /// Get this error's backtrace.
748 ///
749 /// Backtraces will be automatically captured on initial `Error` creation
750 /// when all of the following conditions are met:
751 ///
752 /// * This crate's `"backtrace"` cargo feature is enabled
753 /// * Rust's `std::backtrace::Backtrace` supports the platform
754 /// * The `RUST_BACKTRACE` or `RUST_LIB_BACKTRACE` environment variables
755 /// are set and non-zero
756 ///
757 /// See [the `std::backtrace::Backtrace`
758 /// documentation](https://doc.rust-lang.org/stable/std/backtrace/struct.Backtrace.html)
759 /// for more details on backtraces.
760 ///
761 /// Note that `std::backtrace::Backtrace` does not provide a
762 /// fallible-capture mechanism that returns an error, rather than aborting
763 /// the process, when it encounters memory exhaustion. If you require
764 /// out-of-memory error handling, do not enable this crate's `"backtrace"`
765 /// cargo feature.
766 ///
767 /// # Example
768 ///
769 /// ```
770 /// # fn _foo() {
771 /// #![cfg(feature = "backtrace")]
772 /// # use wasmtime_internal_error as wasmtime;
773 /// use std::backtrace::BacktraceStatus;
774 /// use wasmtime::Error;
775 ///
776 /// let error = Error::msg("whoops");
777 ///
778 /// let backtrace = error.backtrace();
779 /// if let BacktraceStatus::Captured = backtrace.status() {
780 /// println!("error backtrace is:\n{backtrace}");
781 /// }
782 /// # }
783 /// ```
784 #[inline]
785 #[cfg(feature = "backtrace")]
786 pub fn backtrace(&self) -> &Backtrace {
787 self.inner.unpack().backtrace()
788 }
789
790 /// Iterate over this error's context chain.
791 ///
792 /// The iterator yields `&(dyn core::error::Error + 'static)` items.
793 ///
794 /// Iterates from the most recently added error context towards the root
795 /// cause.
796 ///
797 /// # Example
798 ///
799 /// ```
800 /// # use wasmtime_internal_error as wasmtime;
801 /// use wasmtime::Error;
802 ///
803 /// let error = Error::msg("root cause");
804 /// let error = error.context("failed to reticulate splines");
805 /// let error = error.context("aborting launch");
806 ///
807 /// let messages: Vec<_> = error.chain().map(|e| e.to_string()).collect();
808 /// assert_eq!(
809 /// messages,
810 /// ["aborting launch", "failed to reticulate splines", "root cause"],
811 /// );
812 /// ```
813 #[inline]
814 pub fn chain(&self) -> Chain<'_> {
815 Chain::new(self.inner.unpack())
816 }
817
818 /// Get the last error in the context chain.
819 ///
820 /// # Example
821 ///
822 /// ```
823 /// # use wasmtime_internal_error as wasmtime;
824 /// use wasmtime::Error;
825 ///
826 /// let error = Error::msg("ghosts");
827 /// let error = error.context("failed to reticulate splines");
828 /// let error = error.context("aborting launch");
829 ///
830 /// assert_eq!(
831 /// error.root_cause().to_string(),
832 /// "ghosts",
833 /// );
834 /// ```
835 #[inline]
836 pub fn root_cause(&self) -> &(dyn core::error::Error + 'static) {
837 self.chain().last().expect("chain is always non-empty")
838 }
839
840 /// Is this an `E` error?
841 ///
842 /// Returns true if any error in the context chain is an `E`.
843 ///
844 /// # Example
845 ///
846 /// ```
847 /// # use wasmtime_internal_error as wasmtime;
848 /// use wasmtime::{Error, OutOfMemory};
849 ///
850 /// let oom = Error::from(OutOfMemory::new());
851 /// assert!(oom.is::<OutOfMemory>());
852 /// assert!(!oom.is::<std::num::TryFromIntError>());
853 ///
854 /// // Here is an example with additional error context.
855 /// let error = Error::from(u8::try_from(u32::MAX).unwrap_err());
856 /// let error = error.context(format!("cannot convert {} into a u8", u32::MAX));
857 /// assert!(
858 /// error.is::<std::num::TryFromIntError>(),
859 /// "root cause is an int conversion failure",
860 /// );
861 /// assert!(
862 /// error.is::<String>(),
863 /// "additional context is a `String`",
864 /// );
865 /// assert!(
866 /// !error.is::<OutOfMemory>(),
867 /// "no error in the chain is an out-of-memory error",
868 /// );
869 /// ```
870 pub fn is<E>(&self) -> bool
871 where
872 E: fmt::Display + fmt::Debug + Send + Sync + 'static,
873 {
874 let mut error = Some(self.inner.unpack());
875 while let Some(e) = error {
876 if e.is::<E>() {
877 return true;
878 } else {
879 error = e.source();
880 }
881 }
882 false
883 }
884
885 /// Downcast this error into an `E`, taking ownership.
886 ///
887 /// If this error is an `E`, then `Ok(E)` is returned. Otherwise,
888 /// `Err(self)` is returned.
889 ///
890 /// If there are multiple instances of `E` in this error's chain, then the
891 /// first (as encountered by [`Error::chain`]'s iteration order) is
892 /// returned.
893 ///
894 /// # Example
895 ///
896 /// ```
897 /// # use wasmtime_internal_error as wasmtime;
898 /// use wasmtime::{Error, OutOfMemory};
899 ///
900 /// let error = Error::msg("whoops");
901 ///
902 /// // `error` is not an `OutOfMemory`.
903 /// let downcasted = error.downcast::<OutOfMemory>();
904 /// assert!(downcasted.is_err());
905 ///
906 /// // Get the original `error` back.
907 /// let error = downcasted.unwrap_err();
908 ///
909 /// // `error` is an `&str`.
910 /// let downcasted = error.downcast::<&str>();
911 /// assert!(downcasted.is_ok());
912 /// assert_eq!(downcasted.unwrap(), "whoops");
913 ///
914 /// // If there are multiple `E`s in the chain, the first in the chain is
915 /// // returned.
916 /// let error = Error::msg("root cause");
917 /// let error = error.context("failed to recombobulate");
918 /// assert_eq!(
919 /// error.downcast::<&str>().unwrap(),
920 /// "failed to recombobulate",
921 /// );
922 /// ```
923 pub fn downcast<E>(self) -> Result<E, Self>
924 where
925 E: fmt::Display + fmt::Debug + Send + Sync + 'static,
926 {
927 if !self.is::<E>() {
928 return Err(self);
929 }
930
931 let mut value = mem::MaybeUninit::<E>::uninit();
932
933 // Safety: this error is an `E` and the given pointer is valid to write
934 // an `E` to.
935 unsafe {
936 self.inner
937 .downcast(TypeId::of::<E>(), NonNull::from(&mut value).cast::<u8>());
938 }
939
940 // Safety: `OomOrDynError::downcast` guarantees that the given pointer's
941 // data is initialized upon successful return.
942 Ok(unsafe { value.assume_init() })
943 }
944
945 /// Downcast this error into a shared `&E` borrow.
946 ///
947 /// If this error is an `E`, then `Some(&E)` is returned. Otherwise, `None`
948 /// is returned.
949 ///
950 /// If there are multiple instances of `E` in this error's chain, then the
951 /// first (as encountered by [`Error::chain`]'s iteration order) is
952 /// returned.
953 ///
954 /// # Example
955 ///
956 /// ```
957 /// # use wasmtime_internal_error as wasmtime;
958 /// use wasmtime::{Error, OutOfMemory};
959 ///
960 /// let error = Error::msg("whoops");
961 ///
962 /// // `error` is not an `OutOfMemory`.
963 /// assert!(error.downcast_ref::<OutOfMemory>().is_none());
964 ///
965 /// // `error` is an `&str`.
966 /// assert!(error.downcast_ref::<&str>().is_some());
967 /// assert_eq!(*error.downcast_ref::<&str>().unwrap(), "whoops");
968 ///
969 /// // If there are multiple `E`s in the chain, the first in the chain is
970 /// // returned.
971 /// let error = Error::msg("root cause");
972 /// let error = error.context("failed to recombobulate");
973 /// assert_eq!(
974 /// *error.downcast_ref::<&str>().unwrap(),
975 /// "failed to recombobulate",
976 /// );
977 /// ```
978 pub fn downcast_ref<E>(&self) -> Option<&E>
979 where
980 E: fmt::Display + fmt::Debug + Send + Sync + 'static,
981 {
982 let mut error = Some(self.inner.unpack());
983 while let Some(e) = error {
984 if e.is::<E>() {
985 return Some(match e {
986 OomOrDynErrorRef::DynError(ptr) => {
987 let ptr = ptr.cast::<ConcreteError<E>>();
988 // Safety: we own the pointer, it is valid for reading,
989 // and we checked that it is an `E`.
990 let r = unsafe { ptr.as_ref() };
991 &r.error
992 }
993 OomOrDynErrorRef::Oom(oom) => {
994 // Note: Even though we know that `E == OutOfMemory`
995 // here, we still have to do this dance to satisfy the
996 // type system.
997 debug_assert_eq!(TypeId::of::<E>(), TypeId::of::<OutOfMemory>());
998 let ptr = NonNull::from(oom);
999 let ptr = ptr.cast::<E>();
1000 // Safety: the pointer points to `oom`, which is valid
1001 // for creating a shared reference to.
1002 unsafe { ptr.as_ref() }
1003 }
1004 });
1005 } else {
1006 error = e.source();
1007 }
1008 }
1009 None
1010 }
1011
1012 /// Downcast this error into an exclusive `&mut E` borrow.
1013 ///
1014 /// If this error is an `E`, then `Some(&mut E)` is returned. Otherwise,
1015 /// `None` is returned.
1016 ///
1017 /// If there are multiple instances of `E` in this error's chain, then the
1018 /// first (as encountered by [`Error::chain`]'s iteration order) is
1019 /// returned.
1020 ///
1021 /// # Example
1022 ///
1023 /// ```
1024 /// # use wasmtime_internal_error as wasmtime;
1025 /// use wasmtime::{Error, OutOfMemory};
1026 ///
1027 /// let mut error = Error::msg("whoops");
1028 ///
1029 /// // `error` is not an `OutOfMemory`.
1030 /// assert!(error.downcast_mut::<OutOfMemory>().is_none());
1031 ///
1032 /// // `error` is an `&str`.
1033 /// assert!(error.downcast_mut::<&str>().is_some());
1034 /// assert_eq!(*error.downcast_mut::<&str>().unwrap(), "whoops");
1035 /// *error.downcast_mut::<&str>().unwrap() = "yikes";
1036 /// assert_eq!(*error.downcast_mut::<&str>().unwrap(), "yikes");
1037 ///
1038 /// // If there are multiple `E`s in the chain, the first in the chain is
1039 /// // returned.
1040 /// let error = Error::msg("root cause");
1041 /// let mut error = error.context("failed to recombobulate");
1042 /// assert_eq!(
1043 /// *error.downcast_mut::<&str>().unwrap(),
1044 /// "failed to recombobulate",
1045 /// );
1046 /// ```
1047 pub fn downcast_mut<E>(&mut self) -> Option<&mut E>
1048 where
1049 E: fmt::Display + fmt::Debug + Send + Sync + 'static,
1050 {
1051 let mut error = Some(self.inner.unpack_mut());
1052 while let Some(mut e) = error.take() {
1053 if e.as_ref().is::<E>() {
1054 return Some(match e {
1055 OomOrDynErrorMut::DynError(ptr) => {
1056 let mut ptr = ptr.cast::<ConcreteError<E>>();
1057 // Safety: we own the pointer, it is valid for reading
1058 // and writing, and we checked that it is an `E`.
1059 let r = unsafe { ptr.as_mut() };
1060 &mut r.error
1061 }
1062 OomOrDynErrorMut::Oom(oom) => {
1063 // Note: Even though we know that `E == OutOfMemory`
1064 // here, we still have to do this dance to satisfy the
1065 // type system.
1066 debug_assert_eq!(TypeId::of::<E>(), TypeId::of::<OutOfMemory>());
1067 let ptr = NonNull::from(oom);
1068 let mut ptr = ptr.cast::<E>();
1069 // Safety: the pointer points to `oom`, which is valid
1070 // for creating an exclusive reference to.
1071 unsafe { ptr.as_mut() }
1072 }
1073 });
1074 } else {
1075 error = e.source_mut();
1076 }
1077 }
1078 None
1079 }
1080
1081 /// Convert this error into a `Box<dyn core::error::Error>`.
1082 ///
1083 /// This is useful for integrating this crate's `Error`s into other
1084 /// universal-error libraries.
1085 ///
1086 /// This functionality is also available via a `From<Error> for Box<dyn
1087 /// core::error::Error + Send + Sync + 'static>>` implementation.
1088 ///
1089 /// # Example
1090 ///
1091 /// ```
1092 /// # fn _foo() {
1093 /// #![cfg(feature = "std")]
1094 /// use std::fmt;
1095 ///
1096 /// /// A stub representing some other error library.
1097 /// #[derive(Debug)]
1098 /// pub struct OtherError {
1099 /// inner: Box<dyn std::error::Error + Send + Sync + 'static>,
1100 /// }
1101 ///
1102 /// impl fmt::Display for OtherError {
1103 /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1104 /// fmt::Display::fmt(&self.inner, f)
1105 /// }
1106 /// }
1107 ///
1108 /// impl std::error::Error for OtherError {
1109 /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1110 /// self.inner.source()
1111 /// }
1112 /// }
1113 ///
1114 /// impl OtherError {
1115 /// /// Create an `OtherError` from another error.
1116 /// pub fn new<E>(error: E) -> Self
1117 /// where
1118 /// E: std::error::Error + Send + Sync + 'static,
1119 /// {
1120 /// OtherError { inner: Box::new(error) }
1121 /// }
1122 ///
1123 /// /// Create an `OtherError` from another, already-boxed error.
1124 /// pub fn from_boxed(error: Box<dyn std::error::Error + Send + Sync + 'static>) -> Self {
1125 /// OtherError { inner: error }
1126 /// }
1127 /// }
1128 ///
1129 /// # use wasmtime_internal_error as wasmtime;
1130 /// use wasmtime::Error;
1131 ///
1132 /// // Create an `Error`.
1133 /// let error = Error::msg("whoopsies");
1134 ///
1135 /// // Convert it into an `OtherError`.
1136 /// let error = OtherError::from_boxed(error.into_boxed_dyn_error());
1137 /// # }
1138 /// ```
1139 #[inline]
1140 pub fn into_boxed_dyn_error(self) -> Box<dyn core::error::Error + Send + Sync + 'static> {
1141 self.inner.into_boxed_dyn_core_error()
1142 }
1143}
1144
1145/// `ErrorExt` wrapper for foreign `core::error::Error` implementations.
1146///
1147/// For `Error::new`'s use only.
1148///
1149/// NB: The `repr(transparent)` is required for safety of the `ErrorExt::ext_is`
1150/// implementation and the casts that are performed using that method's return
1151/// value.
1152#[repr(transparent)]
1153struct ForeignError<E>(E);
1154
1155// Safety: `ext_is` is correct, `ext_move` always writes to `dest`.
1156unsafe impl<E> ErrorExt for ForeignError<E>
1157where
1158 E: core::error::Error + Send + Sync + 'static,
1159{
1160 fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
1161 &self.0
1162 }
1163
1164 fn ext_into_boxed_dyn_core_error(
1165 self,
1166 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> {
1167 let boxed = try_new_uninit_box()?;
1168 Ok(Box::write(boxed, self.0) as _)
1169 }
1170
1171 fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> {
1172 None
1173 }
1174
1175 fn ext_source_mut(&mut self) -> Option<OomOrDynErrorMut<'_>> {
1176 None
1177 }
1178
1179 fn ext_take_source(&mut self) -> Option<OomOrDynError> {
1180 None
1181 }
1182
1183 unsafe fn ext_move(self, dest: NonNull<u8>) {
1184 // Safety: implied by this trait method's safety contract.
1185 unsafe {
1186 dest.cast::<E>().write(self.0);
1187 }
1188 }
1189
1190 fn ext_is(&self, type_id: TypeId) -> bool {
1191 // NB: need to check type id of `E`, not `Self` aka
1192 // `ForeignError<E>`.
1193 type_id == TypeId::of::<E>()
1194 }
1195
1196 #[cfg(feature = "backtrace")]
1197 fn take_backtrace(&mut self) -> Option<Backtrace> {
1198 None
1199 }
1200}
1201
1202/// `ErrorExt` wrapper for types given to `Error::msg`.
1203///
1204/// For `Error::msg`'s use only.
1205///
1206/// NB: The `repr(transparent)` is required for safety of the `ErrorExt::ext_is`
1207/// implementation and the casts that are performed using that method's return
1208/// value.
1209#[repr(transparent)]
1210struct MessageError<M>(M);
1211
1212impl<M> fmt::Debug for MessageError<M>
1213where
1214 M: fmt::Debug,
1215{
1216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1217 self.0.fmt(f)
1218 }
1219}
1220
1221impl<M> fmt::Display for MessageError<M>
1222where
1223 M: fmt::Display,
1224{
1225 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1226 self.0.fmt(f)
1227 }
1228}
1229
1230impl<M> core::error::Error for MessageError<M> where M: fmt::Debug + fmt::Display {}
1231
1232// Safety: `ext_is` is implemented correctly and `ext_move` always
1233// writes to its pointer.
1234unsafe impl<M> ErrorExt for MessageError<M>
1235where
1236 M: fmt::Debug + fmt::Display + Send + Sync + 'static,
1237{
1238 fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
1239 self
1240 }
1241
1242 fn ext_into_boxed_dyn_core_error(
1243 self,
1244 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> {
1245 let boxed = try_new_uninit_box()?;
1246 Ok(Box::write(boxed, self) as _)
1247 }
1248
1249 fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> {
1250 None
1251 }
1252
1253 fn ext_source_mut(&mut self) -> Option<OomOrDynErrorMut<'_>> {
1254 None
1255 }
1256
1257 fn ext_take_source(&mut self) -> Option<OomOrDynError> {
1258 None
1259 }
1260
1261 fn ext_is(&self, type_id: TypeId) -> bool {
1262 // NB: need to check type id of `M`, not `Self` aka
1263 // `MessageError<M>`.
1264 type_id == TypeId::of::<M>()
1265 }
1266
1267 unsafe fn ext_move(self, dest: NonNull<u8>) {
1268 // Safety: implied by this trait method's contract.
1269 unsafe {
1270 dest.cast::<M>().write(self.0);
1271 }
1272 }
1273
1274 #[cfg(feature = "backtrace")]
1275 fn take_backtrace(&mut self) -> Option<Backtrace> {
1276 None
1277 }
1278}
1279
1280/// `ErrorExt` wrapper for `Box<dyn core::error::Error>`.
1281///
1282/// For `Error::from_boxed`'s use only.
1283///
1284/// NB: The `repr(transparent)` is required for safety of the `ErrorExt::ext_is`
1285/// implementation and the casts that are performed using that method's return
1286/// value.
1287#[repr(transparent)]
1288struct BoxedError(Box<dyn core::error::Error + Send + Sync + 'static>);
1289
1290// Safety: `ext_is` is implemented correctly and `ext_move` always
1291// writes to its pointer.
1292unsafe impl ErrorExt for BoxedError {
1293 fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
1294 &*self.0
1295 }
1296
1297 fn ext_into_boxed_dyn_core_error(
1298 self,
1299 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> {
1300 Ok(self.0)
1301 }
1302
1303 fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> {
1304 None
1305 }
1306
1307 fn ext_source_mut(&mut self) -> Option<OomOrDynErrorMut<'_>> {
1308 None
1309 }
1310
1311 fn ext_take_source(&mut self) -> Option<OomOrDynError> {
1312 None
1313 }
1314
1315 fn ext_is(&self, type_id: TypeId) -> bool {
1316 // NB: need to check type id of `BoxDynSendSyncError`, not
1317 // `BoxedError`.
1318 type_id == TypeId::of::<Box<dyn core::error::Error + Send + Sync + 'static>>()
1319 }
1320
1321 unsafe fn ext_move(self, dest: NonNull<u8>) {
1322 // Safety: implied by this trait method's contract.
1323 unsafe {
1324 dest.cast::<Box<dyn core::error::Error + Send + Sync + 'static>>()
1325 .write(self.0);
1326 }
1327 }
1328
1329 #[cfg(feature = "backtrace")]
1330 fn take_backtrace(&mut self) -> Option<Backtrace> {
1331 None
1332 }
1333}
1334
1335/// `ErrorExt` wrapper for `anyhow::Error`.
1336///
1337/// For `Error::from_anyhow`'s use only.
1338///
1339/// NB: The `repr(transparent)` is required for safety of the `ErrorExt::ext_is`
1340/// implementation and the casts that are performed using that method's return
1341/// value.
1342#[repr(transparent)]
1343#[cfg(feature = "anyhow")]
1344struct AnyhowError(anyhow::Error);
1345
1346// Safety: `ext_is` is implemented correctly and `ext_move` always
1347// writes to its pointer.
1348#[cfg(feature = "anyhow")]
1349unsafe impl ErrorExt for AnyhowError {
1350 fn ext_as_dyn_core_error(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
1351 self.0.as_ref()
1352 }
1353
1354 fn ext_into_boxed_dyn_core_error(
1355 self,
1356 ) -> Result<Box<dyn core::error::Error + Send + Sync + 'static>, OutOfMemory> {
1357 Ok(self.0.into_boxed_dyn_error())
1358 }
1359
1360 fn ext_source(&self) -> Option<OomOrDynErrorRef<'_>> {
1361 None
1362 }
1363
1364 fn ext_source_mut(&mut self) -> Option<OomOrDynErrorMut<'_>> {
1365 None
1366 }
1367
1368 fn ext_take_source(&mut self) -> Option<OomOrDynError> {
1369 None
1370 }
1371
1372 fn ext_is(&self, type_id: TypeId) -> bool {
1373 // NB: need to check type id of `BoxDynSendSyncError`, not
1374 // `AnyhowError`.
1375 type_id == TypeId::of::<anyhow::Error>()
1376 }
1377
1378 unsafe fn ext_move(self, dest: NonNull<u8>) {
1379 // Safety: implied by this trait method's contract.
1380 unsafe {
1381 dest.cast::<anyhow::Error>().write(self.0);
1382 }
1383 }
1384
1385 #[cfg(feature = "backtrace")]
1386 fn take_backtrace(&mut self) -> Option<Backtrace> {
1387 None
1388 }
1389}
1390
1391pub(crate) enum OomOrDynErrorRef<'a> {
1392 // Safety: this must always be a valid pointer to read a `DynError` from for
1393 // the `'a` lifetime.
1394 DynError(SharedPtr<'a, DynError>),
1395
1396 Oom(&'a OutOfMemory),
1397}
1398
1399impl<'a> Debug for OomOrDynErrorRef<'a> {
1400 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1401 self.debug(f)
1402 }
1403}
1404
1405impl<'a> OomOrDynErrorRef<'a> {
1406 fn display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1407 match self {
1408 OomOrDynErrorRef::DynError(e) => {
1409 // Safety: invariant of this type.
1410 let vtable = unsafe { e.as_ref().vtable };
1411 // Safety: using the vtable associated with this pointer's
1412 // concrete type and the pointer is valid.
1413 unsafe { (vtable.display)(*e, f) }
1414 }
1415 OomOrDynErrorRef::Oom(oom) => fmt::Display::fmt(oom, f),
1416 }
1417 }
1418
1419 fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1420 match *self {
1421 OomOrDynErrorRef::Oom(oom) => f.debug_tuple("Oom").field(oom).finish(),
1422 OomOrDynErrorRef::DynError(error) => {
1423 struct DebugError<'a>(SharedPtr<'a, DynError>);
1424 impl fmt::Debug for DebugError<'_> {
1425 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1426 // Safety: invariant of `OomOrDynError` that the pointer
1427 // is valid.
1428 let vtable = unsafe { self.0.as_ref().vtable };
1429 // Safety: the pointer is valid and the vtable is
1430 // associated with the pointer's concrete error type.
1431 unsafe { (vtable.debug)(self.0, f) }
1432 }
1433 }
1434
1435 let mut f = f.debug_struct("DynError");
1436 f.field("error", &DebugError(error));
1437 if let Some(source) = self.source() {
1438 f.field("source", &source);
1439 }
1440 f.finish()
1441 }
1442 }
1443 }
1444
1445 fn source(&self) -> Option<OomOrDynErrorRef<'a>> {
1446 match self {
1447 OomOrDynErrorRef::DynError(e) => {
1448 // Safety: invariant of this type.
1449 let vtable = unsafe { e.as_ref().vtable };
1450 // Safety: using the vtable associated with this pointer's
1451 // concrete type and the pointer is valid.
1452 unsafe { (vtable.source)(*e) }
1453 }
1454 OomOrDynErrorRef::Oom(_) => None,
1455 }
1456 }
1457
1458 fn is<E>(&self) -> bool
1459 where
1460 E: fmt::Display + fmt::Debug + Send + Sync + 'static,
1461 {
1462 match self {
1463 OomOrDynErrorRef::DynError(e) => {
1464 // Safety: invariant of this type.
1465 let vtable = unsafe { e.as_ref().vtable };
1466 // Safety: using the vtable associated with this pointer's
1467 // concrete type and the pointer is valid.
1468 unsafe { (vtable.is)(*e, TypeId::of::<E>()) }
1469 }
1470 OomOrDynErrorRef::Oom(_) => TypeId::of::<E>() == TypeId::of::<OutOfMemory>(),
1471 }
1472 }
1473
1474 pub(crate) fn as_dyn_core_error(&self) -> &'a (dyn core::error::Error + Send + Sync + 'static) {
1475 match *self {
1476 OomOrDynErrorRef::DynError(e) => {
1477 // Safety: invariant of this type.
1478 let vtable = unsafe { e.as_ref().vtable };
1479 // Safety: using the vtable associated with this pointer's
1480 // concrete type and the pointer is valid.
1481 unsafe { (vtable.as_dyn_core_error)(e) }
1482 }
1483 OomOrDynErrorRef::Oom(oom) => oom as _,
1484 }
1485 }
1486
1487 #[cfg(feature = "backtrace")]
1488 fn backtrace(&self) -> &'a Backtrace {
1489 match self {
1490 OomOrDynErrorRef::DynError(e) => {
1491 // Safety: invariant of this type.
1492 let r = unsafe { e.as_ref() };
1493 r.backtrace
1494 .as_ref()
1495 .expect("the first error in the chain always has the backtrace")
1496 }
1497
1498 OomOrDynErrorRef::Oom(_) => {
1499 static DISABLED: Backtrace = Backtrace::disabled();
1500 &DISABLED
1501 }
1502 }
1503 }
1504}
1505
1506pub(crate) enum OomOrDynErrorMut<'a> {
1507 // Safety: this must always be a valid pointer to read and write a
1508 // `DynError` from for the `'a` lifetime.
1509 DynError(MutPtr<'a, DynError>),
1510
1511 Oom(&'a mut OutOfMemory),
1512}
1513
1514impl<'a> OomOrDynErrorMut<'a> {
1515 fn as_ref(&self) -> OomOrDynErrorRef<'_> {
1516 match self {
1517 OomOrDynErrorMut::DynError(e) => OomOrDynErrorRef::DynError(e.as_shared_ptr()),
1518 OomOrDynErrorMut::Oom(oom) => OomOrDynErrorRef::Oom(oom),
1519 }
1520 }
1521
1522 fn source_mut(&mut self) -> Option<OomOrDynErrorMut<'a>> {
1523 match self {
1524 OomOrDynErrorMut::DynError(e) => {
1525 // Safety: invariant of this type.
1526 let vtable = unsafe { e.as_ref().vtable };
1527 // Safety: using the vtable associated with this pointer's
1528 // concrete type and the pointer is valid.
1529 unsafe { (vtable.source_mut)(e.raw_copy()) }
1530 }
1531 OomOrDynErrorMut::Oom(_) => None,
1532 }
1533 }
1534}
1535
1536/// Bit packed version of `enum { BoxedDynError, OutOfMemory }` that relies on
1537/// implicit pointer tagging and `OutOfMemory` being zero-sized.
1538#[repr(transparent)]
1539pub(crate) struct OomOrDynError {
1540 // Safety: this must always be the casted-to-`u8` version of either (a)
1541 // `0x1`, or (b) a valid, owned `DynError` pointer. (Note that these cases
1542 // cannot overlap because `DynError`'s alignment is greater than `0x1`.)
1543 inner: NonNull<u8>,
1544}
1545
1546// Safety: `OomOrDynError` is either an `OutOfMemory` or a `BoxedDynError` and
1547// both are `Send`.
1548unsafe impl Send for OomOrDynError {}
1549
1550// Safety: `OomOrDynError` is either an `OutOfMemory` or a `BoxedDynError` and
1551// both are `Sync`.
1552unsafe impl Sync for OomOrDynError {}
1553
1554const _OOM_OR_DYN_ERROR_SEND_SYNC_SAFETY: () = {
1555 const fn assert_send_sync<T: Send + Sync>() {}
1556 assert_send_sync::<OutOfMemory>();
1557 assert_send_sync::<BoxedDynError>();
1558};
1559
1560impl Drop for OomOrDynError {
1561 fn drop(&mut self) {
1562 if self.is_boxed_dyn_error() {
1563 let inner = self.inner.cast::<DynError>();
1564 let inner = OwnedPtr::new(inner);
1565 // Safety: the pointer is a valid `DynError` pointer.
1566 let _ = unsafe { BoxedDynError::from_owned_ptr(inner) };
1567 } else {
1568 debug_assert!(self.is_oom());
1569 }
1570 }
1571}
1572
1573impl From<BoxedDynError> for OomOrDynError {
1574 fn from(boxed: BoxedDynError) -> Self {
1575 let inner = boxed.into_owned_ptr().into_non_null().cast::<u8>();
1576 debug_assert_ne!(inner, Self::OOM.inner);
1577 OomOrDynError { inner }
1578 }
1579}
1580
1581impl OomOrDynError {
1582 const _SIZE: () = assert!(mem::size_of::<OomOrDynError>() == mem::size_of::<usize>());
1583
1584 // Our pointer tagging relies on this property.
1585 const _DYN_ERROR_HAS_GREATER_ALIGN_THAN_OOM: () = assert!(mem::align_of::<DynError>() > 1);
1586
1587 const OOM_REPR: NonNull<u8> = unsafe {
1588 // Safety: `0x1` is not null.
1589 NonNull::<u8>::new_unchecked(0x1 as *mut u8)
1590 };
1591
1592 pub(crate) const OOM: Self = OomOrDynError {
1593 inner: Self::OOM_REPR,
1594 };
1595
1596 fn is_oom(&self) -> bool {
1597 self.inner == Self::OOM_REPR
1598 }
1599
1600 fn is_boxed_dyn_error(&self) -> bool {
1601 !self.is_oom()
1602 }
1603
1604 /// # Safety
1605 ///
1606 /// `self.is_oom()` must be true.
1607 unsafe fn unchecked_oom(&self) -> &OutOfMemory {
1608 debug_assert!(self.is_oom());
1609 let dangling = NonNull::<OutOfMemory>::dangling();
1610 debug_assert_eq!(mem::size_of::<OutOfMemory>(), 0);
1611 // Safety: it is always valid to turn `T`'s dangling pointer into an
1612 // `&T` reference for unit types.
1613 unsafe { dangling.as_ref() }
1614 }
1615
1616 /// # Safety
1617 ///
1618 /// `self.is_oom()` must be true.
1619 unsafe fn unchecked_oom_mut(&mut self) -> &mut OutOfMemory {
1620 debug_assert!(self.is_oom());
1621 let mut dangling = NonNull::<OutOfMemory>::dangling();
1622 debug_assert_eq!(mem::size_of::<OutOfMemory>(), 0);
1623 // Safety: it is always valid to turn `T`'s dangling pointer into an
1624 // `&mut T` reference for unit types.
1625 unsafe { dangling.as_mut() }
1626 }
1627
1628 /// # Safety
1629 ///
1630 /// `self.is_boxed_dyn_error()` must be true.
1631 unsafe fn unchecked_into_dyn_error(self) -> OwnedPtr<DynError> {
1632 debug_assert!(self.is_boxed_dyn_error());
1633 let inner = self.inner.cast::<DynError>();
1634 mem::forget(self);
1635 OwnedPtr::new(inner)
1636 }
1637
1638 /// # Safety
1639 ///
1640 /// `self.is_boxed_dyn_error()` must be true.
1641 unsafe fn unchecked_dyn_error_ref(&self) -> SharedPtr<'_, DynError> {
1642 debug_assert!(self.is_boxed_dyn_error());
1643 SharedPtr::new(self.inner.cast::<DynError>())
1644 }
1645
1646 /// # Safety
1647 ///
1648 /// `self.is_boxed_dyn_error()` must be true.
1649 unsafe fn unchecked_dyn_error_mut(&mut self) -> MutPtr<'_, DynError> {
1650 debug_assert!(self.is_boxed_dyn_error());
1651 MutPtr::new(self.inner.cast::<DynError>())
1652 }
1653
1654 pub(crate) fn unpack(&self) -> OomOrDynErrorRef<'_> {
1655 if self.is_oom() {
1656 // Safety: is_oom() is true.
1657 OomOrDynErrorRef::Oom(unsafe { self.unchecked_oom() })
1658 } else {
1659 debug_assert!(self.is_boxed_dyn_error());
1660 // Safety: self.is_boxed_dyn_error() is true.
1661 OomOrDynErrorRef::DynError(unsafe { self.unchecked_dyn_error_ref() })
1662 }
1663 }
1664
1665 pub(crate) fn unpack_mut(&mut self) -> OomOrDynErrorMut<'_> {
1666 if self.is_oom() {
1667 // Safety: self.is_oom() is true
1668 OomOrDynErrorMut::Oom(unsafe { self.unchecked_oom_mut() })
1669 } else {
1670 debug_assert!(self.is_boxed_dyn_error());
1671 // Safety: self.is_boxed_dyn_error() is true.
1672 OomOrDynErrorMut::DynError(unsafe { self.unchecked_dyn_error_mut() })
1673 }
1674 }
1675
1676 pub(crate) fn into_boxed_dyn_core_error(
1677 self,
1678 ) -> Box<dyn core::error::Error + Send + Sync + 'static> {
1679 let box_dyn_error_of_oom = || {
1680 // NB: `Box::new` will never actually allocate for zero-sized types
1681 // like `OutOfMemory`.
1682 Box::new(OutOfMemory::new()) as _
1683 };
1684
1685 if self.is_oom() {
1686 box_dyn_error_of_oom()
1687 } else {
1688 debug_assert!(self.is_boxed_dyn_error());
1689 // Safety: this is a boxed dyn error.
1690 let ptr = unsafe { self.unchecked_into_dyn_error() };
1691 // Safety: invariant of the type that the pointer is valid.
1692 let vtable = unsafe { ptr.as_ref().vtable };
1693 // Safety: the pointer is valid and the vtable is associated with
1694 // this pointer's concrete error type.
1695 match unsafe { (vtable.into_boxed_dyn_core_error)(ptr) } {
1696 Ok(e) => e,
1697 Err(_oom) => box_dyn_error_of_oom(),
1698 }
1699 }
1700 }
1701
1702 /// Given that this is known to be an instance of the type associated with
1703 /// the given `TypeId`, do an owning-downcast to that type, writing the
1704 /// result through the given `ret_ptr`, and deallocating `self` along the
1705 /// way.
1706 ///
1707 /// The `ret_ptr`'s storage will contain an initialized instance of the
1708 /// associated type upon this method's successful return.
1709 ///
1710 /// # Safety
1711 ///
1712 /// This error (or another in its chain) must be of the type associated with
1713 /// `TypeId`.
1714 ///
1715 /// The given `ret_ptr` must point to a valid-but-uninitialized storage
1716 /// location for an instance of the type associated with the given `TypeId`.
1717 pub(crate) unsafe fn downcast(self, type_id: TypeId, ret_ptr: NonNull<u8>) {
1718 if self.is_oom() {
1719 debug_assert_eq!(type_id, TypeId::of::<OutOfMemory>());
1720 // Safety: this is an OOM error.
1721 let oom = unsafe { self.unchecked_oom() };
1722 // Safety: implied by this method's safety contract.
1723 unsafe {
1724 ret_ptr.cast::<OutOfMemory>().write(*oom);
1725 }
1726 } else {
1727 debug_assert!(self.is_boxed_dyn_error());
1728 // Safety: this is a boxed dyn error.
1729 let ptr = unsafe { self.unchecked_into_dyn_error() };
1730 // Safety: invariant of this type that the pointer is valid.
1731 let vtable = unsafe { ptr.as_ref().vtable };
1732 // Safety: the pointer is valid and the vtable is associated with
1733 // this pointer's concrete type.
1734 unsafe { (vtable.downcast)(ptr, type_id, ret_ptr) }
1735 }
1736 }
1737}
1738
1739/// An iterator over each error in an [`Error`]'s context chain.
1740///
1741/// The iterator yields `&'a (dyn core::error::Error + 'static)` items.
1742///
1743/// Iterates from the most recently added error context towards the root cause.
1744///
1745/// Created by the [`Error::chain`] method. See that method's documentation for
1746/// more details.
1747pub struct Chain<'a> {
1748 state: ChainState<'a>,
1749}
1750
1751enum ChainState<'a> {
1752 Ours(OomOrDynErrorRef<'a>),
1753 Core(Option<&'a (dyn core::error::Error + 'static)>),
1754}
1755
1756impl<'a> Chain<'a> {
1757 fn new(error: OomOrDynErrorRef<'a>) -> Self {
1758 Self {
1759 state: ChainState::Ours(error),
1760 }
1761 }
1762}
1763
1764impl<'a> Iterator for Chain<'a> {
1765 type Item = &'a (dyn core::error::Error + 'static);
1766
1767 #[inline]
1768 fn next(&mut self) -> Option<Self::Item> {
1769 match &mut self.state {
1770 ChainState::Ours(e) => {
1771 let core = e.as_dyn_core_error();
1772 self.state = if let Some(e) = e.source() {
1773 ChainState::Ours(e)
1774 } else {
1775 ChainState::Core(core.source())
1776 };
1777 Some(core)
1778 }
1779 ChainState::Core(error) => {
1780 let e = error.take()?;
1781 self.state = ChainState::Core(e.source());
1782 Some(e)
1783 }
1784 }
1785 }
1786}
1787
1788impl FusedIterator for Chain<'_> {}
1789
1790#[cfg(test)]
1791mod tests {
1792 use super::*;
1793
1794 #[derive(Debug)]
1795 struct TestError;
1796
1797 impl fmt::Display for TestError {
1798 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1799 fmt::Debug::fmt(self, f)
1800 }
1801 }
1802
1803 impl core::error::Error for TestError {}
1804
1805 #[test]
1806 fn from_oom() {
1807 let mut error = Error::from(OutOfMemory::new());
1808 assert!(error.is::<OutOfMemory>());
1809 assert!(error.downcast_ref::<OutOfMemory>().is_some());
1810 assert!(error.downcast_mut::<OutOfMemory>().is_some());
1811
1812 // NB: use this module's scope to check that the inner representation is
1813 // `OomOrDynError::Oom` and not a `Box<OutOfMemory> as Box<dyn
1814 // Error>`. This is why this test cannot be in `tests/tests.rs`.
1815 assert!(error.inner.is_oom());
1816 }
1817
1818 #[test]
1819 fn dyn_error_and_concrete_error_layouts_are_compatible() {
1820 type Concrete = ConcreteError<TestError>;
1821
1822 let dyn_size = mem::size_of::<DynError>();
1823 let concrete_size = mem::size_of::<Concrete>();
1824 assert!(
1825 dyn_size <= concrete_size,
1826 "assertion failed: {dyn_size} <= {concrete_size}"
1827 );
1828
1829 let dyn_align = mem::align_of::<DynError>();
1830 let concrete_align = mem::align_of::<Concrete>();
1831 assert!(
1832 dyn_align <= concrete_align,
1833 "assertion failed: {dyn_align} <= {concrete_align}"
1834 );
1835
1836 let dyn_offset = mem::offset_of!(DynError, vtable);
1837 let concrete_offset = mem::offset_of!(Concrete, vtable);
1838 assert_eq!(dyn_offset, concrete_offset);
1839
1840 #[cfg(feature = "backtrace")]
1841 {
1842 let dyn_offset = mem::offset_of!(DynError, backtrace);
1843 let concrete_offset = mem::offset_of!(Concrete, backtrace);
1844 assert_eq!(dyn_offset, concrete_offset);
1845 }
1846 }
1847}