Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support disabling backtraces at compile time #3932

Merged
merged 2 commits into from
Mar 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ jobs:
- run: cargo check -p wasmtime --no-default-features --features uffd
- run: cargo check -p wasmtime --no-default-features --features pooling-allocator
- run: cargo check -p wasmtime --no-default-features --features cranelift
- run: cargo check -p wasmtime --no-default-features --features cranelift,wat,async,cache
- run: cargo check -p wasmtime --no-default-features --features wasm-backtrace
- run: cargo check -p wasmtime --no-default-features --features cranelift,wat,async,cache,wasm-backtrace

# Check that benchmarks of the cranelift project build
- run: cargo check --benches -p cranelift-codegen
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ default = [
"wasi-nn",
"pooling-allocator",
"memory-init-cow",
"wasm-backtrace",
]
jitdump = ["wasmtime/jitdump"]
vtune = ["wasmtime/vtune"]
Expand All @@ -109,6 +110,7 @@ memory-init-cow = ["wasmtime/memory-init-cow"]
pooling-allocator = ["wasmtime/pooling-allocator"]
all-arch = ["wasmtime/all-arch"]
posix-signals-on-macos = ["wasmtime/posix-signals-on-macos"]
wasm-backtrace = ["wasmtime/wasm-backtrace"]

# Stub feature that does nothing, for Cargo-features compatibility: the new
# backend is the default now.
Expand Down
2 changes: 1 addition & 1 deletion crates/c-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ doctest = false
env_logger = "0.8"
anyhow = "1.0"
once_cell = "1.3"
wasmtime = { path = "../wasmtime", default-features = false, features = ['cranelift'] }
wasmtime = { path = "../wasmtime", default-features = false, features = ['cranelift', 'wasm-backtrace'] }
wasmtime-c-api-macros = { path = "macros" }

# Optional dependency for the `wat2wasm` API
Expand Down
20 changes: 14 additions & 6 deletions crates/cranelift/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,13 @@ impl wasmtime_environ::Compiler for Compiler {

let stack_maps = mach_stack_maps_to_stack_maps(result.buffer.stack_maps());

let unwind_info = context
.create_unwind_info(isa)
.map_err(|error| CompileError::Codegen(pretty_error(&context.func, error)))?;
let unwind_info = if isa.flags().unwind_info() {
context
.create_unwind_info(isa)
.map_err(|error| CompileError::Codegen(pretty_error(&context.func, error)))?
} else {
None
};

let address_transform =
self.get_function_address_map(&context, &input, code_buf.len() as u32, tunables);
Expand Down Expand Up @@ -566,9 +570,13 @@ impl Compiler {
.relocs()
.is_empty());

let unwind_info = context
.create_unwind_info(isa)
.map_err(|error| CompileError::Codegen(pretty_error(&context.func, error)))?;
let unwind_info = if isa.flags().unwind_info() {
context
.create_unwind_info(isa)
.map_err(|error| CompileError::Codegen(pretty_error(&context.func, error)))?
} else {
None
};

Ok(CompiledFunction {
body: code_buf,
Expand Down
4 changes: 2 additions & 2 deletions crates/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ indexmap = "1.0.2"
thiserror = "1.0.4"
more-asserts = "0.2.1"
cfg-if = "1.0"
backtrace = "0.3.61"
backtrace = { version = "0.3.61", optional = true }
rand = "0.8.3"
anyhow = "1.0.38"
memfd = { version = "0.4.1", optional = true }
Expand All @@ -46,8 +46,8 @@ cc = "1.0"
maintenance = { status = "actively-developed" }

[features]
default = []
memory-init-cow = ['memfd']
wasm-backtrace = ["backtrace"]

async = ["wasmtime-fiber"]

Expand Down
6 changes: 5 additions & 1 deletion crates/runtime/src/externref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,7 @@ impl VMExternRefActivationsTable {
}
}

#[cfg_attr(not(feature = "wasm-backtrace"), allow(dead_code))]
fn insert_precise_stack_root(
precise_stack_roots: &mut HashSet<VMExternRefWithTraits>,
root: NonNull<VMExternData>,
Expand Down Expand Up @@ -866,6 +867,7 @@ impl<T> std::ops::DerefMut for DebugOnly<T> {
///
/// Additionally, you must have registered the stack maps for every Wasm module
/// that has frames on the stack with the given `stack_maps_registry`.
#[cfg_attr(not(feature = "wasm-backtrace"), allow(unused_mut, unused_variables))]
pub unsafe fn gc(
module_info_lookup: &dyn ModuleInfoLookup,
externref_activations_table: &mut VMExternRefActivationsTable,
Expand Down Expand Up @@ -893,6 +895,7 @@ pub unsafe fn gc(
None => {
if cfg!(debug_assertions) {
// Assert that there aren't any Wasm frames on the stack.
#[cfg(feature = "wasm-backtrace")]
backtrace::trace(|frame| {
assert!(module_info_lookup.lookup(frame.ip() as usize).is_none());
true
Expand All @@ -917,7 +920,7 @@ pub unsafe fn gc(
// newly-discovered precise set.

// The SP of the previous (younger) frame we processed.
let mut last_sp = None;
let mut last_sp: Option<usize> = None;

// Whether we have found our stack canary or not yet.
let mut found_canary = false;
Expand All @@ -934,6 +937,7 @@ pub unsafe fn gc(
});
}

#[cfg(feature = "wasm-backtrace")]
backtrace::trace(|frame| {
let pc = frame.ip() as usize;
let sp = frame.sp() as usize;
Expand Down
2 changes: 1 addition & 1 deletion crates/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub use crate::mmap_vec::MmapVec;
pub use crate::table::{Table, TableElement};
pub use crate::traphandlers::{
catch_traps, init_traps, raise_lib_trap, raise_user_trap, resume_panic, tls_eager_initialize,
SignalHandler, TlsRestore, Trap,
Backtrace, SignalHandler, TlsRestore, Trap,
};
pub use crate::vmcontext::{
VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport, VMGlobalDefinition,
Expand Down
6 changes: 1 addition & 5 deletions crates/runtime/src/libcalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ use crate::instance::Instance;
use crate::table::{Table, TableElementType};
use crate::traphandlers::{raise_lib_trap, resume_panic, Trap};
use crate::vmcontext::{VMCallerCheckedAnyfunc, VMContext};
use backtrace::Backtrace;
use std::mem;
use std::ptr::{self, NonNull};
use wasmtime_environ::{
Expand Down Expand Up @@ -588,10 +587,7 @@ unsafe fn validate_atomic_addr(
addr: usize,
) -> Result<(), Trap> {
if addr > instance.get_memory(memory).current_length {
return Err(Trap::Wasm {
trap_code: TrapCode::HeapOutOfBounds,
backtrace: Backtrace::new_unresolved(),
});
return Err(Trap::wasm(TrapCode::HeapOutOfBounds));
}
Ok(())
}
Expand Down
40 changes: 34 additions & 6 deletions crates/runtime/src/traphandlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

use crate::VMContext;
use anyhow::Error;
use backtrace::Backtrace;
use std::any::Any;
use std::cell::{Cell, UnsafeCell};
use std::mem::MaybeUninit;
Expand Down Expand Up @@ -143,19 +142,48 @@ impl Trap {
///
/// Internally saves a backtrace when constructed.
pub fn wasm(trap_code: TrapCode) -> Self {
let backtrace = Backtrace::new_unresolved();
Trap::Wasm {
trap_code,
backtrace,
backtrace: Backtrace::new(),
}
}

/// Construct a new OOM trap with the given source location and trap code.
///
/// Internally saves a backtrace when constructed.
pub fn oom() -> Self {
let backtrace = Backtrace::new_unresolved();
Trap::OOM { backtrace }
Trap::OOM {
backtrace: Backtrace::new(),
}
}
}

/// A crate-local backtrace type which conditionally, at compile time, actually
/// contains a backtrace from the `backtrace` crate or nothing.
#[derive(Debug)]
pub struct Backtrace {
#[cfg(feature = "wasm-backtrace")]
trace: backtrace::Backtrace,
}

impl Backtrace {
/// Captures a new backtrace
///
/// Note that this function does nothing if the `wasm-backtrace` feature is
/// disabled.
pub fn new() -> Backtrace {
Backtrace {
#[cfg(feature = "wasm-backtrace")]
trace: backtrace::Backtrace::new_unresolved(),
}
}

/// Returns the backtrace frames associated with this backtrace. Note that
/// this is conditionally defined and not present when `wasm-backtrace` is
/// not present.
#[cfg(feature = "wasm-backtrace")]
pub fn frames(&self) -> &[backtrace::BacktraceFrame] {
self.trace.frames()
}
}

Expand Down Expand Up @@ -299,7 +327,7 @@ impl CallThreadState {
}

fn capture_backtrace(&self, pc: *const u8) {
let backtrace = Backtrace::new_unresolved();
let backtrace = Backtrace::new();
unsafe {
(*self.unwind.get())
.as_mut_ptr()
Expand Down
9 changes: 8 additions & 1 deletion crates/wasmtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ anyhow = "1.0.19"
region = "2.2.0"
libc = "0.2"
cfg-if = "1.0"
backtrace = "0.3.61"
backtrace = { version = "0.3.61", optional = true }
log = "0.4.8"
wat = { version = "1.0.36", optional = true }
serde = { version = "1.0.94", features = ["derive"] }
Expand Down Expand Up @@ -61,6 +61,7 @@ default = [
'pooling-allocator',
'memory-init-cow',
'vtune',
'wasm-backtrace',
]

# An on-by-default feature enabling runtime compilation of WebAssembly modules
Expand Down Expand Up @@ -108,3 +109,9 @@ posix-signals-on-macos = ["wasmtime-runtime/posix-signals-on-macos"]
# Enabling this feature has no effect on unsupported platforms or when the
# `uffd` feature is enabled.
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"]
27 changes: 22 additions & 5 deletions crates/wasmtime/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ 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);
Expand Down Expand Up @@ -502,10 +504,14 @@ impl Config {
/// Note that enabling the reference types feature will also enable the bulk
/// memory feature.
///
/// This is `true` by default on x86-64, and `false` by default on other
/// architectures.
/// 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.
///
/// [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;

Expand Down Expand Up @@ -1272,9 +1278,20 @@ impl Config {

#[cfg(compiler)]
fn compiler_builder(strategy: Strategy) -> Result<Box<dyn CompilerBuilder>> {
match strategy {
Strategy::Auto | Strategy::Cranelift => Ok(wasmtime_cranelift::builder()),
}
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)
}

fn round_up_to_pages(val: u64) -> u64 {
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmtime/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,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(true),
"unwind_info" => *value == FlagValue::Bool(cfg!(feature = "wasm-backtrace")),
"libcall_call_conv" => *value == FlagValue::Enum("isa_default".into()),

// Features wasmtime doesn't use should all be disabled, since
Expand Down
8 changes: 8 additions & 0 deletions crates/wasmtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,14 @@
//! 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
Expand Down
Loading