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