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