1 use crate::prelude::*; 2 use 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. 26 macro_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 36 pub(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)] 46 pub struct WasmtimeBug { 47 message: String, 48 file: &'static str, 49 line: u32, 50 } 51 52 impl WasmtimeBug { 53 #[cold] new(message: fmt::Arguments<'_>, pos: &'static (&'static str, u32)) -> Self54 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 66 impl fmt::Display for WasmtimeBug { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 68 write!( 69 f, 70 "\ 71 BUG: {} 72 location: {}:{} 73 version: {} 74 75 This is a bug in Wasmtime that was not thought to be reachable. A panic is 76 not happening to avoid taking down the thread, but this trap is being injected 77 into WebAssembly guests to prevent their execution. The Wasmtime project would 78 appreciate a bug report with a copy of this message to help investigate what 79 happened. If you're able to provide a reproduction, that would be appreciated, 80 but it is not necessary to do so and instead indicating that this is reachable 81 is 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 92 impl core::error::Error for WasmtimeBug {} 93