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