make backtrace collection a Config field rather than a cargo feature (#4183)
* sorta working in runtime * wasmtime-runtime: get rid of wasm-backtrace feature * wasmtime: factor to make backtraces recording optional. not configurable yet * get rid of wasm-backtrace features * trap tests: now a Trap optionally contains backtrace * eliminate wasm-backtrace feature * code review fixes * ci: no more wasm-backtrace feature * c_api: backtraces always enabled * config: unwind required by backtraces and ref types * plumbed * test that disabling backtraces works * code review comments * fuzzing generator: wasm_backtrace is a runtime config now * doc fix
This commit is contained in:
@@ -25,7 +25,7 @@ anyhow = "1.0.19"
|
||||
region = "2.2.0"
|
||||
libc = "0.2"
|
||||
cfg-if = "1.0"
|
||||
backtrace = { version = "0.3.61", optional = true }
|
||||
backtrace = { version = "0.3.61" }
|
||||
log = "0.4.8"
|
||||
wat = { version = "1.0.43", optional = true }
|
||||
serde = { version = "1.0.94", features = ["derive"] }
|
||||
@@ -37,7 +37,7 @@ lazy_static = "1.4"
|
||||
rayon = { version = "1.0", optional = true }
|
||||
object = { version = "0.28", default-features = false, features = ['read_core', 'elf'] }
|
||||
async-trait = { version = "0.1.51", optional = true }
|
||||
once_cell = "1.9"
|
||||
once_cell = "1.12"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = "0.3.7"
|
||||
@@ -61,7 +61,6 @@ default = [
|
||||
'pooling-allocator',
|
||||
'memory-init-cow',
|
||||
'vtune',
|
||||
'wasm-backtrace',
|
||||
]
|
||||
|
||||
# An on-by-default feature enabling runtime compilation of WebAssembly modules
|
||||
@@ -106,12 +105,6 @@ posix-signals-on-macos = ["wasmtime-runtime/posix-signals-on-macos"]
|
||||
# Enabling this feature has no effect on unsupported platforms.
|
||||
memory-init-cow = ["wasmtime-runtime/memory-init-cow"]
|
||||
|
||||
# Enables runtime support necessary to capture backtraces of WebAssembly code
|
||||
# that is running.
|
||||
#
|
||||
# This is enabled by default.
|
||||
wasm-backtrace = ["wasmtime-runtime/wasm-backtrace", "backtrace"]
|
||||
|
||||
# Enables in-progress support for the component model. Note that this feature is
|
||||
# in-progress, buggy, and incomplete. This is primarily here for internal
|
||||
# testing purposes.
|
||||
|
||||
@@ -91,6 +91,7 @@ pub struct Config {
|
||||
pub(crate) allocation_strategy: InstanceAllocationStrategy,
|
||||
pub(crate) max_wasm_stack: usize,
|
||||
pub(crate) features: WasmFeatures,
|
||||
pub(crate) wasm_backtrace: bool,
|
||||
pub(crate) wasm_backtrace_details_env_used: bool,
|
||||
#[cfg(feature = "async")]
|
||||
pub(crate) async_stack_size: usize,
|
||||
@@ -124,6 +125,7 @@ impl Config {
|
||||
// 1` forces this), or at least it passed when this change was
|
||||
// committed.
|
||||
max_wasm_stack: 512 * 1024,
|
||||
wasm_backtrace: true,
|
||||
wasm_backtrace_details_env_used: false,
|
||||
features: WasmFeatures::default(),
|
||||
#[cfg(feature = "async")]
|
||||
@@ -140,9 +142,7 @@ impl Config {
|
||||
ret.cranelift_debug_verifier(false);
|
||||
ret.cranelift_opt_level(OptLevel::Speed);
|
||||
}
|
||||
#[cfg(feature = "wasm-backtrace")]
|
||||
ret.wasm_reference_types(true);
|
||||
ret.features.reference_types = cfg!(feature = "wasm-backtrace");
|
||||
ret.wasm_multi_value(true);
|
||||
ret.wasm_bulk_memory(true);
|
||||
ret.wasm_simd(true);
|
||||
@@ -279,6 +279,35 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures whether backtraces exist in a `Trap`.
|
||||
///
|
||||
/// Enabled by default, this feature builds in support to
|
||||
/// generate backtraces at runtime for WebAssembly modules. This means that
|
||||
/// unwinding information is compiled into wasm modules and necessary runtime
|
||||
/// dependencies are enabled as well.
|
||||
///
|
||||
/// When disabled, wasm backtrace details are ignored, and [`crate::Trap::trace()`]
|
||||
/// will always return `None`.
|
||||
|
||||
pub fn wasm_backtrace(&mut self, enable: bool) -> &mut Self {
|
||||
self.wasm_backtrace = enable;
|
||||
#[cfg(compiler)]
|
||||
{
|
||||
// unwind_info must be enabled when either backtraces or reference types are enabled:
|
||||
self.compiler
|
||||
.set(
|
||||
"unwind_info",
|
||||
if enable || self.features.reference_types {
|
||||
"true"
|
||||
} else {
|
||||
"false"
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Configures whether backtraces in `Trap` will parse debug info in the wasm file to
|
||||
/// have filename/line number information.
|
||||
///
|
||||
@@ -508,14 +537,9 @@ impl Config {
|
||||
/// Note that enabling the reference types feature will also enable the bulk
|
||||
/// memory feature.
|
||||
///
|
||||
/// This feature is `true` by default. If the `wasm-backtrace` feature is
|
||||
/// disabled at compile time, however, then this is `false` by default and
|
||||
/// it cannot be turned on since GC currently requires backtraces to work.
|
||||
/// Note that the `wasm-backtrace` feature is on by default, however.
|
||||
/// This feature is `true` by default.
|
||||
///
|
||||
/// [proposal]: https://github.com/webassembly/reference-types
|
||||
#[cfg(feature = "wasm-backtrace")]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "wasm-backtrace")))]
|
||||
pub fn wasm_reference_types(&mut self, enable: bool) -> &mut Self {
|
||||
self.features.reference_types = enable;
|
||||
|
||||
@@ -524,6 +548,17 @@ impl Config {
|
||||
self.compiler
|
||||
.set("enable_safepoints", if enable { "true" } else { "false" })
|
||||
.unwrap();
|
||||
// unwind_info must be enabled when either backtraces or reference types are enabled:
|
||||
self.compiler
|
||||
.set(
|
||||
"unwind_info",
|
||||
if enable || self.wasm_backtrace {
|
||||
"true"
|
||||
} else {
|
||||
"false"
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// The reference types proposal depends on the bulk memory proposal.
|
||||
@@ -1288,20 +1323,9 @@ impl Config {
|
||||
|
||||
#[cfg(compiler)]
|
||||
fn compiler_builder(strategy: Strategy) -> Result<Box<dyn CompilerBuilder>> {
|
||||
let mut builder = match strategy {
|
||||
Strategy::Auto | Strategy::Cranelift => wasmtime_cranelift::builder(),
|
||||
};
|
||||
builder
|
||||
.set(
|
||||
"unwind_info",
|
||||
if cfg!(feature = "wasm-backtrace") {
|
||||
"true"
|
||||
} else {
|
||||
"false"
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
Ok(builder)
|
||||
match strategy {
|
||||
Strategy::Auto | Strategy::Cranelift => Ok(wasmtime_cranelift::builder()),
|
||||
}
|
||||
}
|
||||
|
||||
fn round_up_to_pages(val: u64) -> u64 {
|
||||
@@ -1331,6 +1355,7 @@ impl Clone for Config {
|
||||
mem_creator: self.mem_creator.clone(),
|
||||
allocation_strategy: self.allocation_strategy.clone(),
|
||||
max_wasm_stack: self.max_wasm_stack,
|
||||
wasm_backtrace: self.wasm_backtrace,
|
||||
wasm_backtrace_details_env_used: self.wasm_backtrace_details_env_used,
|
||||
async_support: self.async_support,
|
||||
#[cfg(feature = "async")]
|
||||
|
||||
@@ -303,7 +303,7 @@ impl Engine {
|
||||
// can affect the way the generated code performs or behaves at
|
||||
// runtime.
|
||||
"avoid_div_traps" => *value == FlagValue::Bool(true),
|
||||
"unwind_info" => *value == FlagValue::Bool(cfg!(feature = "wasm-backtrace")),
|
||||
"unwind_info" => *value == FlagValue::Bool(true),
|
||||
"libcall_call_conv" => *value == FlagValue::Enum("isa_default".into()),
|
||||
|
||||
// Features wasmtime doesn't use should all be disabled, since
|
||||
|
||||
@@ -1235,6 +1235,7 @@ pub(crate) fn invoke_wasm_and_catch_traps<T>(
|
||||
}
|
||||
let result = wasmtime_runtime::catch_traps(
|
||||
store.0.signal_handler(),
|
||||
store.0.engine().config().wasm_backtrace,
|
||||
store.0.default_callee(),
|
||||
closure,
|
||||
);
|
||||
|
||||
@@ -290,14 +290,6 @@
|
||||
//! run-time via [`Config::memory_init_cow`] (which is also enabled by
|
||||
//! default).
|
||||
//!
|
||||
//! * `wasm-backtrace` - Enabled by default, this feature builds in support to
|
||||
//! generate backtraces at runtime for WebAssembly modules. This means that
|
||||
//! unwinding information is compiled into wasm modules and necessary runtime
|
||||
//! dependencies are enabled as well. If this is turned off then some methods
|
||||
//! to look at trap frames will not be available. Additionally at this time
|
||||
//! disabling this feature means that the reference types feature is always
|
||||
//! disabled as well.
|
||||
//!
|
||||
//! ## Examples
|
||||
//!
|
||||
//! In addition to the examples below be sure to check out the [online embedding
|
||||
|
||||
@@ -1914,11 +1914,7 @@ unsafe impl<T> wasmtime_runtime::Store for StoreInner<T> {
|
||||
fn new_epoch(&mut self) -> Result<u64, anyhow::Error> {
|
||||
return match &mut self.epoch_deadline_behavior {
|
||||
EpochDeadline::Trap => {
|
||||
let trap = Trap::new_wasm(
|
||||
None,
|
||||
wasmtime_environ::TrapCode::Interrupt,
|
||||
wasmtime_runtime::Backtrace::new(),
|
||||
);
|
||||
let trap = Trap::new_wasm(wasmtime_environ::TrapCode::Interrupt, None);
|
||||
Err(anyhow::Error::from(trap))
|
||||
}
|
||||
EpochDeadline::Callback(callback) => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::module::GlobalModuleRegistry;
|
||||
use crate::FrameInfo;
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use wasmtime_environ::TrapCode as EnvTrapCode;
|
||||
@@ -127,95 +128,18 @@ impl fmt::Display for TrapCode {
|
||||
}
|
||||
}
|
||||
|
||||
struct TrapInner {
|
||||
reason: TrapReason,
|
||||
#[cfg(feature = "wasm-backtrace")]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct TrapBacktrace {
|
||||
wasm_trace: Vec<FrameInfo>,
|
||||
native_trace: Backtrace,
|
||||
#[cfg(feature = "wasm-backtrace")]
|
||||
hint_wasm_backtrace_details_env: bool,
|
||||
}
|
||||
|
||||
fn _assert_trap_is_sync_and_send(t: &Trap) -> (&dyn Sync, &dyn Send) {
|
||||
(t, t)
|
||||
}
|
||||
|
||||
impl Trap {
|
||||
/// Creates a new `Trap` with `message`.
|
||||
/// # Example
|
||||
/// ```
|
||||
/// let trap = wasmtime::Trap::new("unexpected error");
|
||||
/// assert!(trap.to_string().contains("unexpected error"));
|
||||
/// ```
|
||||
#[cold] // traps are exceptional, this helps move handling off the main path
|
||||
pub fn new<I: Into<String>>(message: I) -> Self {
|
||||
let reason = TrapReason::Message(message.into());
|
||||
Trap::new_with_trace(None, reason, Backtrace::new())
|
||||
}
|
||||
|
||||
/// Creates a new `Trap` representing an explicit program exit with a classic `i32`
|
||||
/// exit status value.
|
||||
#[cold] // see Trap::new
|
||||
pub fn i32_exit(status: i32) -> Self {
|
||||
Trap::new_with_trace(None, TrapReason::I32Exit(status), Backtrace::new())
|
||||
}
|
||||
|
||||
#[cold] // see Trap::new
|
||||
pub(crate) fn from_runtime_box(runtime_trap: Box<wasmtime_runtime::Trap>) -> Self {
|
||||
Self::from_runtime(*runtime_trap)
|
||||
}
|
||||
|
||||
#[cold] // see Trap::new
|
||||
pub(crate) fn from_runtime(runtime_trap: wasmtime_runtime::Trap) -> Self {
|
||||
match runtime_trap {
|
||||
wasmtime_runtime::Trap::User(error) => Trap::from(error),
|
||||
wasmtime_runtime::Trap::Jit { pc, backtrace } => {
|
||||
let code = GlobalModuleRegistry::with(|modules| {
|
||||
modules
|
||||
.lookup_trap_code(pc)
|
||||
.unwrap_or(EnvTrapCode::StackOverflow)
|
||||
});
|
||||
Trap::new_wasm(Some(pc), code, backtrace)
|
||||
}
|
||||
wasmtime_runtime::Trap::Wasm {
|
||||
trap_code,
|
||||
backtrace,
|
||||
} => Trap::new_wasm(None, trap_code, backtrace),
|
||||
wasmtime_runtime::Trap::OOM { backtrace } => {
|
||||
let reason = TrapReason::Message("out of memory".to_string());
|
||||
Trap::new_with_trace(None, reason, backtrace)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cold] // see Trap::new
|
||||
pub(crate) fn new_wasm(
|
||||
trap_pc: Option<usize>,
|
||||
code: EnvTrapCode,
|
||||
backtrace: Backtrace,
|
||||
) -> Self {
|
||||
let code = TrapCode::from_non_user(code);
|
||||
Trap::new_with_trace(trap_pc, TrapReason::InstructionTrap(code), backtrace)
|
||||
}
|
||||
|
||||
/// Creates a new `Trap`.
|
||||
///
|
||||
/// * `trap_pc` - this is the precise program counter, if available, that
|
||||
/// wasm trapped at. This is used when learning about the wasm stack trace
|
||||
/// to ensure we assign the correct source to every frame.
|
||||
///
|
||||
/// * `reason` - this is the wasmtime-internal reason for why this trap is
|
||||
/// being created.
|
||||
///
|
||||
/// * `native_trace` - this is a captured backtrace from when the trap
|
||||
/// occurred, and this will iterate over the frames to find frames that
|
||||
/// lie in wasm jit code.
|
||||
#[cfg_attr(not(feature = "wasm-backtrace"), allow(unused_mut, unused_variables))]
|
||||
fn new_with_trace(trap_pc: Option<usize>, reason: TrapReason, native_trace: Backtrace) -> Self {
|
||||
impl TrapBacktrace {
|
||||
pub fn new(native_trace: Backtrace, trap_pc: Option<usize>) -> Self {
|
||||
let mut wasm_trace = Vec::<FrameInfo>::new();
|
||||
let mut hint_wasm_backtrace_details_env = false;
|
||||
|
||||
#[cfg(feature = "wasm-backtrace")]
|
||||
GlobalModuleRegistry::with(|registry| {
|
||||
for frame in native_trace.frames() {
|
||||
let pc = frame.ip() as usize;
|
||||
@@ -250,15 +174,103 @@ impl Trap {
|
||||
}
|
||||
}
|
||||
});
|
||||
Self {
|
||||
wasm_trace,
|
||||
native_trace,
|
||||
hint_wasm_backtrace_details_env,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TrapInner {
|
||||
reason: TrapReason,
|
||||
backtrace: OnceCell<TrapBacktrace>,
|
||||
}
|
||||
|
||||
fn _assert_trap_is_sync_and_send(t: &Trap) -> (&dyn Sync, &dyn Send) {
|
||||
(t, t)
|
||||
}
|
||||
|
||||
impl Trap {
|
||||
/// Creates a new `Trap` with `message`.
|
||||
/// # Example
|
||||
/// ```
|
||||
/// let trap = wasmtime::Trap::new("unexpected error");
|
||||
/// assert!(trap.to_string().contains("unexpected error"));
|
||||
/// ```
|
||||
#[cold] // traps are exceptional, this helps move handling off the main path
|
||||
pub fn new<I: Into<String>>(message: I) -> Self {
|
||||
let reason = TrapReason::Message(message.into());
|
||||
Trap::new_with_trace(reason, None)
|
||||
}
|
||||
|
||||
/// Creates a new `Trap` representing an explicit program exit with a classic `i32`
|
||||
/// exit status value.
|
||||
#[cold] // see Trap::new
|
||||
pub fn i32_exit(status: i32) -> Self {
|
||||
Trap::new_with_trace(TrapReason::I32Exit(status), None)
|
||||
}
|
||||
|
||||
#[cold] // see Trap::new
|
||||
pub(crate) fn from_runtime_box(runtime_trap: Box<wasmtime_runtime::Trap>) -> Self {
|
||||
Self::from_runtime(*runtime_trap)
|
||||
}
|
||||
|
||||
#[cold] // see Trap::new
|
||||
pub(crate) fn from_runtime(runtime_trap: wasmtime_runtime::Trap) -> Self {
|
||||
match runtime_trap {
|
||||
wasmtime_runtime::Trap::User { error, backtrace } => {
|
||||
let trap = Trap::from(error);
|
||||
if let Some(backtrace) = backtrace {
|
||||
trap.record_backtrace(TrapBacktrace::new(backtrace, None));
|
||||
}
|
||||
trap
|
||||
}
|
||||
wasmtime_runtime::Trap::Jit { pc, backtrace } => {
|
||||
let code = GlobalModuleRegistry::with(|modules| {
|
||||
modules
|
||||
.lookup_trap_code(pc)
|
||||
.unwrap_or(EnvTrapCode::StackOverflow)
|
||||
});
|
||||
let backtrace = backtrace.map(|bt| TrapBacktrace::new(bt, Some(pc)));
|
||||
Trap::new_wasm(code, backtrace)
|
||||
}
|
||||
wasmtime_runtime::Trap::Wasm {
|
||||
trap_code,
|
||||
backtrace,
|
||||
} => {
|
||||
let backtrace = backtrace.map(|bt| TrapBacktrace::new(bt, None));
|
||||
Trap::new_wasm(trap_code, backtrace)
|
||||
}
|
||||
wasmtime_runtime::Trap::OOM { backtrace } => {
|
||||
let reason = TrapReason::Message("out of memory".to_string());
|
||||
let backtrace = backtrace.map(|bt| TrapBacktrace::new(bt, None));
|
||||
Trap::new_with_trace(reason, backtrace)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cold] // see Trap::new
|
||||
pub(crate) fn new_wasm(code: EnvTrapCode, backtrace: Option<TrapBacktrace>) -> Self {
|
||||
let code = TrapCode::from_non_user(code);
|
||||
Trap::new_with_trace(TrapReason::InstructionTrap(code), backtrace)
|
||||
}
|
||||
|
||||
/// Creates a new `Trap`.
|
||||
/// * `reason` - this is the wasmtime-internal reason for why this trap is
|
||||
/// being created.
|
||||
///
|
||||
/// * `backtrace` - this is a captured backtrace from when the trap
|
||||
/// occurred. Contains the native backtrace, and the backtrace of
|
||||
/// WebAssembly frames.
|
||||
fn new_with_trace(reason: TrapReason, backtrace: Option<TrapBacktrace>) -> Self {
|
||||
let backtrace = if let Some(bt) = backtrace {
|
||||
OnceCell::with_value(bt)
|
||||
} else {
|
||||
OnceCell::new()
|
||||
};
|
||||
Trap {
|
||||
inner: Arc::new(TrapInner {
|
||||
reason,
|
||||
native_trace,
|
||||
#[cfg(feature = "wasm-backtrace")]
|
||||
wasm_trace,
|
||||
#[cfg(feature = "wasm-backtrace")]
|
||||
hint_wasm_backtrace_details_env,
|
||||
}),
|
||||
inner: Arc::new(TrapInner { reason, backtrace }),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,10 +295,12 @@ impl Trap {
|
||||
|
||||
/// Returns a list of function frames in WebAssembly code that led to this
|
||||
/// trap happening.
|
||||
#[cfg(feature = "wasm-backtrace")]
|
||||
#[cfg_attr(nightlydoc, doc(cfg(feature = "wasm-backtrace")))]
|
||||
pub fn trace(&self) -> &[FrameInfo] {
|
||||
&self.inner.wasm_trace
|
||||
pub fn trace(&self) -> Option<&[FrameInfo]> {
|
||||
self.inner
|
||||
.backtrace
|
||||
.get()
|
||||
.as_ref()
|
||||
.map(|bt| bt.wasm_trace.as_slice())
|
||||
}
|
||||
|
||||
/// Code of a trap that happened while executing a WASM instruction.
|
||||
@@ -297,16 +311,26 @@ impl Trap {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn record_backtrace(&self, backtrace: TrapBacktrace) {
|
||||
// When a trap is created on top of the wasm stack, the trampoline will
|
||||
// re-raise it via
|
||||
// `wasmtime_runtime::raise_user_trap(trap.into::<Box<dyn Error>>())`
|
||||
// after panic::catch_unwind. We don't want to overwrite the first
|
||||
// backtrace recorded, as it is most precise.
|
||||
// FIXME: make sure backtraces are only created once per trap! they are
|
||||
// actually kinda expensive to create.
|
||||
let _ = self.inner.backtrace.try_insert(backtrace);
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Trap {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut f = f.debug_struct("Trap");
|
||||
f.field("reason", &self.inner.reason);
|
||||
#[cfg(feature = "wasm-backtrace")]
|
||||
{
|
||||
f.field("wasm_trace", &self.inner.wasm_trace)
|
||||
.field("native_trace", &self.inner.native_trace);
|
||||
if let Some(backtrace) = self.inner.backtrace.get() {
|
||||
f.field("wasm_trace", &backtrace.wasm_trace)
|
||||
.field("native_trace", &backtrace.native_trace);
|
||||
}
|
||||
f.finish()
|
||||
}
|
||||
@@ -316,15 +340,13 @@ impl fmt::Display for Trap {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.inner.reason)?;
|
||||
|
||||
#[cfg(feature = "wasm-backtrace")]
|
||||
{
|
||||
let trace = self.trace();
|
||||
if let Some(trace) = self.trace() {
|
||||
if trace.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
writeln!(f, "\nwasm backtrace:")?;
|
||||
|
||||
for (i, frame) in self.trace().iter().enumerate() {
|
||||
for (i, frame) in trace.iter().enumerate() {
|
||||
let name = frame.module_name().unwrap_or("<unknown>");
|
||||
write!(f, " {:>3}: ", i)?;
|
||||
|
||||
@@ -369,7 +391,13 @@ impl fmt::Display for Trap {
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.inner.hint_wasm_backtrace_details_env {
|
||||
if self
|
||||
.inner
|
||||
.backtrace
|
||||
.get()
|
||||
.map(|t| t.hint_wasm_backtrace_details_env)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
writeln!(f, "note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable to may show more debugging information")?;
|
||||
}
|
||||
}
|
||||
@@ -404,7 +432,7 @@ impl From<Box<dyn std::error::Error + Send + Sync>> for Trap {
|
||||
trap.clone()
|
||||
} else {
|
||||
let reason = TrapReason::Error(e.into());
|
||||
Trap::new_with_trace(None, reason, Backtrace::new())
|
||||
Trap::new_with_trace(reason, None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user