Skip to main content

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 {}