Skip to content
New issue

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

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

Already on GitHub? # to your account

Memcheck for Wasm guests in Wasmtime #6820

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7689549
attempt at inserting things where i think they might belong + questions
ssunkin-fastly Jun 29, 2023
3402c15
entry hook + questions
ssunkin-fastly Jul 5, 2023
b999de6
commented out all changes, doc comment errors
ssunkin-fastly Jul 13, 2023
77d72b2
fix doc comment
awortman-fastly Jul 17, 2023
ebda2a2
libcalls build now!!!!
awortman-fastly Jul 17, 2023
f962078
initial check_malloc_exit setup
awortman-fastly Jul 17, 2023
18389d7
WIP: load/store hooks
cfallin Jul 17, 2023
4e713b1
hooks added + building
ssunkin-fastly Jul 19, 2023
2586e24
added valgrind library
ssunkin-fastly Jul 19, 2023
e4d7a0c
made wasm-valgrind accessible in wasmtime
iximeow Jul 19, 2023
adde43c
check_malloc filled in...
ssunkin-fastly Jul 19, 2023
13035b1
move valgrind_state to an appropriate part of instance
iximeow Jul 19, 2023
759b129
yay it's working! (?) i think??
ssunkin-fastly Jul 19, 2023
efd9343
stack tracing in progress
ssunkin-fastly Jul 20, 2023
c94c0f7
errors + num bytes displayed
ssunkin-fastly Jul 28, 2023
74990f2
initial valgrind configuration
ssunkin-fastly Jul 31, 2023
6e89201
valgrind conditional some warnings fixed
ssunkin-fastly Jul 31, 2023
59ff0aa
conditional compilation + CLI flag finished
ssunkin-fastly Aug 2, 2023
8f5df30
panic!() changed to bail!()
ssunkin-fastly Aug 3, 2023
e2d929c
started adding doc comments
ssunkin-fastly Aug 7, 2023
3e9e823
added memory grow hook + fixed access size handling
ssunkin-fastly Aug 8, 2023
0bb2290
removed test.wasm
ssunkin-fastly Aug 8, 2023
fe3db2a
removed malloc_twice.wat
ssunkin-fastly Aug 8, 2023
c108c5f
doc comments in spec.rs
ssunkin-fastly Aug 8, 2023
316dfb5
Merge upstream/main into wasmtime-valgrind-hacking
ssunkin-fastly Aug 9, 2023
36bbfd9
pr feedback addressed
ssunkin-fastly Aug 10, 2023
f4947a5
ran cargo fmt
ssunkin-fastly Aug 10, 2023
6c896f2
addressing more feedback
ssunkin-fastly Aug 10, 2023
e1a1855
Remove fuzz crate from wmemcheck.
cfallin Aug 10, 2023
62e3461
Review feedback and test fix.
cfallin Aug 10, 2023
0acc9da
add wasmtime-wmemcheck crate to publish allowlist.
cfallin Aug 10, 2023
e2c8af1
fix build without compiler features
cfallin Aug 11, 2023
a222399
reorder crates in publish list
cfallin Aug 11, 2023
b820b50
Add trampolines for libcalls on s390x.
cfallin Aug 14, 2023
7db34f6
Make wasmtime-wmemcheck dep an exact version requirement.
cfallin Aug 14, 2023
8a4a8d4
Merge remote-tracking branch 'upstream/main' into wasmtime-valgrind-h…
cfallin Aug 16, 2023
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
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ jobs:
- run: cargo check -p wasmtime --no-default-features --features component-model
- run: cargo check -p wasmtime --no-default-features --features cranelift,wat,async,cache
- run: cargo check -p wasmtime --no-default-features --features winch
- run: cargo check -p wasmtime --no-default-features --features wmemcheck
- run: cargo check --features component-model
- run: cargo check -p wasmtime --features incremental-cache

Expand Down
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ members = [
"crates/test-programs/wasi-http-tests",
"crates/test-programs/command-tests",
"crates/test-programs/reactor-tests",
"crates/wmemcheck",
"crates/wasi-preview1-component-adapter",
"crates/wasi-preview1-component-adapter/verify",
"crates/winch",
Expand All @@ -112,7 +113,7 @@ members = [
]
exclude = [
'crates/wasi-common/WASI/tools/witx-cli',
'docs/rust_wasi_markdown_parser'
'docs/rust_wasi_markdown_parser',
]

[workspace.package]
Expand All @@ -122,6 +123,7 @@ edition = "2021"
rust-version = "1.66.0"

[workspace.dependencies]
wasmtime-wmemcheck = { path = "crates/wmemcheck", version = "=13.0.0" }
wasmtime = { path = "crates/wasmtime", version = "13.0.0", default-features = false }
wasmtime-cache = { path = "crates/cache", version = "=13.0.0" }
wasmtime-cli-flags = { path = "crates/cli-flags", version = "=13.0.0" }
Expand Down Expand Up @@ -271,6 +273,7 @@ component-model = [
"wasmtime-cli-flags/component-model"
]
winch = ["wasmtime/winch"]
wmemcheck = ["wasmtime/wmemcheck"]

[[test]]
name = "host_segfault"
Expand Down
59 changes: 34 additions & 25 deletions cranelift/wasm/src/code_translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
}
debug_assert_eq!(ty, builder.func.dfg.value_type(val));
builder.ins().store(flags, val, addr, offset);
environ.update_global(builder, *global_index, val);
}
GlobalVariable::Custom => {
let val = state.pop1();
Expand Down Expand Up @@ -588,6 +589,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
};
{
let return_args = state.peekn_mut(return_count);
environ.handle_before_return(&return_args, builder);
bitcast_wasm_returns(environ, return_args, builder);
builder.ins().return_(return_args);
}
Expand Down Expand Up @@ -757,6 +759,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let heap_index = MemoryIndex::from_u32(*mem);
let heap = state.get_heap(builder.func, *mem, environ)?;
let val = state.pop1();
environ.before_memory_grow(builder, val, heap_index);
state.push1(environ.translate_memory_grow(builder.cursor(), heap_index, heap, val)?)
}
Operator::MemorySize { mem, mem_byte: _ } => {
Expand Down Expand Up @@ -859,47 +862,48 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
);
}
Operator::V128Load8x8S { memarg } => {
let (flags, base) = unwrap_or_return_unreachable_state!(
//TODO(#6829): add before_load() and before_store() hooks for SIMD loads and stores.
let (flags, _, base) = unwrap_or_return_unreachable_state!(
state,
prepare_addr(memarg, 8, builder, state, environ)?
);
let loaded = builder.ins().sload8x8(flags, base, 0);
state.push1(loaded);
}
Operator::V128Load8x8U { memarg } => {
let (flags, base) = unwrap_or_return_unreachable_state!(
let (flags, _, base) = unwrap_or_return_unreachable_state!(
state,
prepare_addr(memarg, 8, builder, state, environ)?
);
let loaded = builder.ins().uload8x8(flags, base, 0);
state.push1(loaded);
}
Operator::V128Load16x4S { memarg } => {
let (flags, base) = unwrap_or_return_unreachable_state!(
let (flags, _, base) = unwrap_or_return_unreachable_state!(
state,
prepare_addr(memarg, 8, builder, state, environ)?
);
let loaded = builder.ins().sload16x4(flags, base, 0);
state.push1(loaded);
}
Operator::V128Load16x4U { memarg } => {
let (flags, base) = unwrap_or_return_unreachable_state!(
let (flags, _, base) = unwrap_or_return_unreachable_state!(
state,
prepare_addr(memarg, 8, builder, state, environ)?
);
let loaded = builder.ins().uload16x4(flags, base, 0);
state.push1(loaded);
}
Operator::V128Load32x2S { memarg } => {
let (flags, base) = unwrap_or_return_unreachable_state!(
let (flags, _, base) = unwrap_or_return_unreachable_state!(
state,
prepare_addr(memarg, 8, builder, state, environ)?
);
let loaded = builder.ins().sload32x2(flags, base, 0);
state.push1(loaded);
}
Operator::V128Load32x2U { memarg } => {
let (flags, base) = unwrap_or_return_unreachable_state!(
let (flags, _, base) = unwrap_or_return_unreachable_state!(
state,
prepare_addr(memarg, 8, builder, state, environ)?
);
Expand Down Expand Up @@ -2631,13 +2635,15 @@ fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>(
/// heap address if execution reaches that point.
///
/// Returns `None` when the Wasm access will unconditionally trap.
///
/// Returns `(flags, wasm_addr, native_addr)`.
fn prepare_addr<FE>(
memarg: &MemArg,
access_size: u8,
builder: &mut FunctionBuilder,
state: &mut FuncTranslationState,
environ: &mut FE,
) -> WasmResult<Reachability<(MemFlags, Value)>>
) -> WasmResult<Reachability<(MemFlags, Value, Value)>>
where
FE: FuncEnvironment + ?Sized,
{
Expand Down Expand Up @@ -2787,7 +2793,7 @@ where
// vmctx, stack) accesses.
flags.set_heap();

Ok(Reachability::Reachable((flags, addr)))
Ok(Reachability::Reachable((flags, index, addr)))
}

fn align_atomic_addr(
Expand Down Expand Up @@ -2834,7 +2840,7 @@ fn prepare_atomic_addr<FE: FuncEnvironment + ?Sized>(
builder: &mut FunctionBuilder,
state: &mut FuncTranslationState,
environ: &mut FE,
) -> WasmResult<Reachability<(MemFlags, Value)>> {
) -> WasmResult<Reachability<(MemFlags, Value, Value)>> {
align_atomic_addr(memarg, loaded_bytes, builder, state);
prepare_addr(memarg, loaded_bytes, builder, state, environ)
}
Expand Down Expand Up @@ -2866,16 +2872,15 @@ fn translate_load<FE: FuncEnvironment + ?Sized>(
state: &mut FuncTranslationState,
environ: &mut FE,
) -> WasmResult<Reachability<()>> {
let (flags, base) = match prepare_addr(
memarg,
mem_op_size(opcode, result_ty),
builder,
state,
environ,
)? {
Reachability::Unreachable => return Ok(Reachability::Unreachable),
Reachability::Reachable((f, b)) => (f, b),
};
let mem_op_size = mem_op_size(opcode, result_ty);
let (flags, wasm_index, base) =
match prepare_addr(memarg, mem_op_size, builder, state, environ)? {
Reachability::Unreachable => return Ok(Reachability::Unreachable),
Reachability::Reachable((f, i, b)) => (f, i, b),
};

environ.before_load(builder, mem_op_size, wasm_index, memarg.offset);

let (load, dfg) = builder
.ins()
.Load(opcode, result_ty, flags, Offset32::new(0), base);
Expand All @@ -2893,11 +2898,15 @@ fn translate_store<FE: FuncEnvironment + ?Sized>(
) -> WasmResult<()> {
let val = state.pop1();
let val_ty = builder.func.dfg.value_type(val);
let mem_op_size = mem_op_size(opcode, val_ty);

let (flags, base) = unwrap_or_return_unreachable_state!(
let (flags, wasm_index, base) = unwrap_or_return_unreachable_state!(
state,
prepare_addr(memarg, mem_op_size(opcode, val_ty), builder, state, environ)?
prepare_addr(memarg, mem_op_size, builder, state, environ)?
);

environ.before_store(builder, mem_op_size, wasm_index, memarg.offset);

builder
.ins()
.Store(opcode, val_ty, flags, Offset32::new(0), val, base);
Expand Down Expand Up @@ -2954,7 +2963,7 @@ fn translate_atomic_rmw<FE: FuncEnvironment + ?Sized>(
arg2 = builder.ins().ireduce(access_ty, arg2);
}

let (flags, addr) = unwrap_or_return_unreachable_state!(
let (flags, _, addr) = unwrap_or_return_unreachable_state!(
state,
prepare_atomic_addr(
memarg,
Expand Down Expand Up @@ -3011,7 +3020,7 @@ fn translate_atomic_cas<FE: FuncEnvironment + ?Sized>(
replacement = builder.ins().ireduce(access_ty, replacement);
}

let (flags, addr) = unwrap_or_return_unreachable_state!(
let (flags, _, addr) = unwrap_or_return_unreachable_state!(
state,
prepare_atomic_addr(
memarg,
Expand Down Expand Up @@ -3054,7 +3063,7 @@ fn translate_atomic_load<FE: FuncEnvironment + ?Sized>(
};
assert!(w_ty_ok && widened_ty.bytes() >= access_ty.bytes());

let (flags, addr) = unwrap_or_return_unreachable_state!(
let (flags, _, addr) = unwrap_or_return_unreachable_state!(
state,
prepare_atomic_addr(
memarg,
Expand Down Expand Up @@ -3103,7 +3112,7 @@ fn translate_atomic_store<FE: FuncEnvironment + ?Sized>(
data = builder.ins().ireduce(access_ty, data);
}

let (flags, addr) = unwrap_or_return_unreachable_state!(
let (flags, _, addr) = unwrap_or_return_unreachable_state!(
state,
prepare_atomic_addr(
memarg,
Expand Down
41 changes: 41 additions & 0 deletions cranelift/wasm/src/environ/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,47 @@ pub trait FuncEnvironment: TargetEnvironment {
fn use_x86_pmaddubsw_for_dot(&self) -> bool {
false
}

/// Inserts code before a function return.
fn handle_before_return(&mut self, _retvals: &[ir::Value], _builder: &mut FunctionBuilder) {}

/// Inserts code before a load.
fn before_load(
&mut self,
_builder: &mut FunctionBuilder,
_val_size: u8,
_addr: ir::Value,
_offset: u64,
) {
}

/// Inserts code before a store.
fn before_store(
&mut self,
_builder: &mut FunctionBuilder,
_val_size: u8,
_addr: ir::Value,
_offset: u64,
) {
}

/// Inserts code before updating a global.
fn update_global(
&mut self,
_builder: &mut FunctionBuilder,
_global_index: u32,
_value: ir::Value,
) {
}

/// Inserts code before memory.grow.
fn before_memory_grow(
&mut self,
_builder: &mut FunctionBuilder,
_num_bytes: ir::Value,
_mem_index: MemoryIndex,
) {
}
}

/// An object satisfying the `ModuleEnvironment` trait can be passed as argument to the
Expand Down
1 change: 1 addition & 0 deletions cranelift/wasm/src/func_translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ fn parse_function_body<FE: FuncEnvironment + ?Sized>(
// generate a return instruction that doesn't match the signature.
if state.reachable {
if !builder.is_unreachable() {
environ.handle_before_return(&state.stack, builder);
bitcast_wasm_returns(environ, &mut state.stack, builder);
builder.ins().return_(&state.stack);
}
Expand Down
2 changes: 2 additions & 0 deletions crates/cranelift/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ target-lexicon = { workspace = true }
gimli = { workspace = true }
object = { workspace = true, features = ['write'] }
thiserror = { workspace = true }
cfg-if = { workspace = true }
wasmtime-versioned-export-macros = { workspace = true }

[features]
all-arch = ["cranelift-codegen/all-arch"]
component-model = ["wasmtime-environ/component-model"]
incremental-cache = ["cranelift-codegen/incremental-cache"]
wmemcheck = []
7 changes: 7 additions & 0 deletions crates/cranelift/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct Builder {
linkopts: LinkOptions,
cache_store: Option<Arc<dyn CacheStore>>,
clif_dir: Option<path::PathBuf>,
wmemcheck: bool,
}

#[derive(Clone, Default)]
Expand All @@ -42,6 +43,7 @@ pub fn builder() -> Box<dyn CompilerBuilder> {
linkopts: LinkOptions::default(),
cache_store: None,
clif_dir: None,
wmemcheck: false,
})
}

Expand Down Expand Up @@ -91,6 +93,7 @@ impl CompilerBuilder for Builder {
self.cache_store.clone(),
self.linkopts.clone(),
self.clif_dir.clone(),
self.wmemcheck,
)))
}

Expand All @@ -105,6 +108,10 @@ impl CompilerBuilder for Builder {
self.cache_store = Some(cache_store);
Ok(())
}

fn wmemcheck(&mut self, enable: bool) {
self.wmemcheck = enable;
}
}

impl fmt::Debug for Builder {
Expand Down
6 changes: 5 additions & 1 deletion crates/cranelift/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ pub(crate) struct Compiler {
linkopts: LinkOptions,
cache_store: Option<Arc<dyn CacheStore>>,
clif_dir: Option<path::PathBuf>,
wmemcheck: bool,
}

impl Drop for Compiler {
Expand Down Expand Up @@ -108,6 +109,7 @@ impl Compiler {
cache_store: Option<Arc<dyn CacheStore>>,
linkopts: LinkOptions,
clif_dir: Option<path::PathBuf>,
wmemcheck: bool,
) -> Compiler {
Compiler {
contexts: Default::default(),
Expand All @@ -116,6 +118,7 @@ impl Compiler {
linkopts,
cache_store,
clif_dir,
wmemcheck,
}
}
}
Expand Down Expand Up @@ -147,7 +150,8 @@ impl wasmtime_environ::Compiler for Compiler {
context.func.collect_debug_info();
}

let mut func_env = FuncEnvironment::new(isa, translation, types, &self.tunables);
let mut func_env =
FuncEnvironment::new(isa, translation, types, &self.tunables, self.wmemcheck);

// The `stack_limit` global value below is the implementation of stack
// overflow checks in Wasmtime.
Expand Down
Loading