wasmtime/runtime/bug.rs
1use crate::prelude::*;
2use core::fmt;
3
4/// Helper macro to `bail!` with a `WasmtimeBug` instance.
5///
6/// This is used in locations in lieu of panicking. The general idea when using
7/// this is:
8///
9/// * The invocation of this cannot be refactored to be statically ruled out.
10/// * The invocation cannot be reasoned about locally to determine that this is
11/// dynamically not reachable.
12///
13/// This macro serves as an alternative to `panic!` which returns a
14/// `WasmtimeBug` instead of panicking. This means that a trap is raised in the
15/// guest and a store is poisoned for example (w.r.t. components). This
16/// primarily serves as a DoS mitigation mechanism where if the panic were
17/// actually hit at runtime it would be a CVE. The worst-case scenario of
18/// raising a trap is that a guest is erroneously terminated, which is a much
19/// more controlled failure mode.
20///
21/// The general guideline for using this is "don't" if you can avoid it because
22/// it's best to either statically rule out these cases or make it verifiable
23/// locally that it can't be hit. When this isn't possible, however, this is a
24/// good alternative to panicking in the case that this is actually executed at
25/// runtime.
26macro_rules! bail_bug {
27 ($($arg:tt)*) => {{
28 // Minimize argument passing to the `new` function by placing the
29 // file/line in a static which is passed by reference to just pass a
30 // single extra pointer argument.
31 static POS: (&'static str, u32) = (file!(), line!());
32 $crate::bail!(crate::WasmtimeBug::new(format_args!($($arg)*), &POS))
33 }}
34}
35
36pub(crate) use bail_bug;
37
38/// Error which indicates a bug in Wasmtime.
39///
40/// This structure is used internally with Wasmtime for situations which are a
41/// bug in Wasmtime but not serious enough to raise a panic and unwind the
42/// current thread of execution. In these situations this is still considered a
43/// bug and a trap is raised to terminate a guest, and it's considered something
44/// that needs to be fixed in Wasmtime.
45#[derive(Debug)]
46pub struct WasmtimeBug {
47 message: String,
48 file: &'static str,
49 line: u32,
50}
51
52impl WasmtimeBug {
53 #[cold]
54 pub(crate) fn new(message: fmt::Arguments<'_>, pos: &'static (&'static str, u32)) -> Self {
55 if cfg!(debug_assertions) {
56 panic!("BUG: {message}");
57 }
58 Self {
59 message: message.to_string(),
60 file: pos.0,
61 line: pos.1,
62 }
63 }
64}
65
66impl fmt::Display for WasmtimeBug {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 write!(
69 f,
70 "\
71BUG: {}
72location: {}:{}
73version: {}
74
75This is a bug in Wasmtime that was not thought to be reachable. A panic is
76not happening to avoid taking down the thread, but this trap is being injected
77into WebAssembly guests to prevent their execution. The Wasmtime project would
78appreciate a bug report with a copy of this message to help investigate what
79happened. If you're able to provide a reproduction, that would be appreciated,
80but it is not necessary to do so and instead indicating that this is reachable
81is a sufficiently actionable bug for maintainers to investigate.
82
83",
84 self.message,
85 self.file,
86 self.line,
87 env!("CARGO_PKG_VERSION"),
88 )
89 }
90}
91
92impl core::error::Error for WasmtimeBug {}