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

Merge with upstream #238

Merged
merged 18 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
12c20b2
Implement the Wasm GC instructions for converting between `anyref` an…
fitzgen Oct 10, 2024
7bdb25e
Remove the now-unused `VMGcRef::as_externref_unchecked` method (#9436)
fitzgen Oct 10, 2024
d5652f5
Implement the `ref.cast` Wasm GC instruction (#9437)
fitzgen Oct 10, 2024
a94c775
Implement the `br_on_cast[_fail]` Wasm GC instructions (#9438)
fitzgen Oct 10, 2024
ae088ed
Update wasm-tools crates to 219.1 (#9439)
fitzgen Oct 10, 2024
866ede9
Document a Wasmtime-specific vulnerability runbook (#9433)
alexcrichton Oct 10, 2024
0146260
Enable some miscellaneous Wasm GC spec tests; fix module import/expor…
fitzgen Oct 10, 2024
f59cad1
Add missing pooling allocator options as CLI flags (#9256) (#9447)
omarjatoi Oct 10, 2024
964360a
Update wit-bindgen dependencies (#9421)
alexcrichton Oct 10, 2024
a8998e7
Update docs/stabilization of wasm proposals (#9434)
alexcrichton Oct 10, 2024
7c96aa1
Implement subtype checking for `[return_]call_indirect` instructions …
fitzgen Oct 10, 2024
1a31606
Add a note about the "X" on GC's "finished" status (#9451)
alexcrichton Oct 10, 2024
ec05264
Add some disas tests for a few more Wasm GC instructions (#9453)
fitzgen Oct 11, 2024
ad6030f
Add a test that fuzzers generate wasm proposals (#9452)
alexcrichton Oct 11, 2024
9529243
Add support for initializing/getting/setting `funcref`s in GC structs…
fitzgen Oct 11, 2024
939917d
Add the `wasmtime::NoneRef` host API type for Wasm's `(ref null? none…
fitzgen Oct 11, 2024
292f136
Centralize wasm-features-in-fuzzing a bit more (#9450)
alexcrichton Oct 11, 2024
0da9592
Merge with upstream
dhil Oct 11, 2024
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
170 changes: 85 additions & 85 deletions Cargo.lock

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -274,19 +274,19 @@ io-lifetimes = { version = "2.0.3", default-features = false }
io-extras = "0.18.1"
rustix = "0.38.31"
# wit-bindgen:
wit-bindgen = { git = "https://github.com/wasmfx/wit-bindgenfx", tag = "v0.33.0", default-features = false }
wit-bindgen-rust-macro = { git = "https://github.com/wasmfx/wit-bindgenfx", tag = "v0.33.0", default-features = false }
wit-bindgen = { git = "https://github.com/wasmfx/wit-bindgenfx", tag = "v0.34.0", default-features = false }
wit-bindgen-rust-macro = { git = "https://github.com/wasmfx/wit-bindgenfx", tag = "v0.34.0", default-features = false }

# wasm-tools family:
wasmparser = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.0", default-features = false }
wat = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.0" }
wast = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.0" }
wasmprinter = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.0" }
wasm-encoder = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.0" }
wasm-smith = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.0" }
wasm-mutate = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.0" }
wit-parser = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.0" }
wit-component = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.0" }
wasmparser = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.1", default-features = false }
wat = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.1" }
wast = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.1" }
wasmprinter = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.1" }
wasm-encoder = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.1" }
wasm-smith = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.1" }
wasm-mutate = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.1" }
wit-parser = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.1" }
wit-component = { git = "https://github.com/wasmfx/wasmfx-tools", tag = "v1.219.1" }

# Non-Bytecode Alliance maintained dependencies:
# --------------------------
Expand Down
2 changes: 1 addition & 1 deletion crates/c-api/src/ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ pub unsafe extern "C" fn wasmtime_externref_data(
externref
.and_then(|e| e.as_wasmtime())
.and_then(|e| {
let data = e.data(cx).ok()?;
let data = e.data(cx).ok()??;
Some(data.downcast_ref::<crate::ForeignData>().unwrap().data)
})
.unwrap_or(ptr::null_mut())
Expand Down
105 changes: 99 additions & 6 deletions crates/cli-flags/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ wasmtime_option_group! {

/// The number of decommits to do per batch. A batch size of 1
/// effectively disables decommit batching. (default: 1)
pub pooling_decommit_batch_size: Option<u32>,
pub pooling_decommit_batch_size: Option<usize>,

/// How many bytes to keep resident between instantiations for the
/// pooling allocator in linear memories.
Expand All @@ -86,7 +86,11 @@ wasmtime_option_group! {

/// Enable memory protection keys for the pooling allocator; this can
/// optimize the size of memory slots.
pub memory_protection_keys: Option<bool>,
pub pooling_memory_protection_keys: Option<bool>,

/// Sets an upper limit on how many memory protection keys (MPK) Wasmtime
/// will use. (default: 16)
pub pooling_max_memory_protection_keys: Option<usize>,

/// Configure attempting to initialize linear memory via a
/// copy-on-write mapping (default: yes)
Expand Down Expand Up @@ -124,6 +128,43 @@ wasmtime_option_group! {
/// when using the pooling allocator.
pub pooling_max_core_instance_size: Option<usize>,

/// Configures the maximum number of "unused warm slots" to retain in the
/// pooling allocator. (default: 100)
pub pooling_max_unused_warm_slots: Option<u32>,

/// Configures whether or not stacks used for async futures are reset to
/// zero after usage. (default: false)
pub pooling_async_stack_zeroing: Option<bool>,

/// How much memory, in bytes, to keep resident for async stacks allocated
/// with the pooling allocator. (default: 0)
pub pooling_async_stack_keep_resident: Option<usize>,

/// The maximum size, in bytes, allocated for a component instance's
/// `VMComponentContext` metadata. (default: 1MiB)
pub pooling_max_component_instance_size: Option<usize>,

/// The maximum number of core instances a single component may contain
/// (default is unlimited).
pub pooling_max_core_instances_per_component: Option<u32>,

/// The maximum number of Wasm linear memories that a single component may
/// transitively contain (default is unlimited).
pub pooling_max_memories_per_component: Option<u32>,

/// The maximum number of tables that a single component may transitively
/// contain (default is unlimited).
pub pooling_max_tables_per_component: Option<u32>,

/// The maximum number of defined tables for a core module. (default: 1)
pub pooling_max_tables_per_module: Option<u32>,

/// The maximum number of defined linear memories for a module. (default: 1)
pub pooling_max_memories_per_module: Option<u32>,

/// The maximum number of concurrent GC heaps supported. (default: 1000)
pub pooling_total_gc_heaps: Option<u32>,

/// Enable or disable the use of host signal handlers for traps.
pub signals_based_traps: Option<bool>,
}
Expand Down Expand Up @@ -663,30 +704,82 @@ impl CommonOptions {
limit => cfg.total_stacks(limit),
_ => err,
}
if let Some(limit) = self.opts.pooling_max_memory_size {
cfg.max_memory_size(limit);
if let Some(max) = self.opts.pooling_max_memory_size {
cfg.max_memory_size(max);
}
if let Some(size) = self.opts.pooling_decommit_batch_size {
cfg.decommit_batch_size(size);
}
if let Some(max) = self.opts.pooling_max_unused_warm_slots {
cfg.max_unused_warm_slots(max);
}
match_feature! {
["async" : self.opts.pooling_async_stack_zeroing]
enable => cfg.async_stack_zeroing(enable),
_ => err,
}
match_feature! {
["async" : self.opts.pooling_async_stack_keep_resident]
size => cfg.async_stack_keep_resident(size),
_ => err,
}
if let Some(max) = self.opts.pooling_max_component_instance_size {
cfg.max_component_instance_size(max);
}
if let Some(max) = self.opts.pooling_max_core_instances_per_component {
cfg.max_core_instances_per_component(max);
}
if let Some(max) = self.opts.pooling_max_memories_per_component {
cfg.max_memories_per_component(max);
}
if let Some(max) = self.opts.pooling_max_tables_per_component {
cfg.max_tables_per_component(max);
}
if let Some(max) = self.opts.pooling_max_tables_per_module {
cfg.max_tables_per_module(max);
}
if let Some(max) = self.opts.pooling_max_memories_per_module {
cfg.max_memories_per_module(max);
}
match_feature! {
["memory-protection-keys" : self.opts.memory_protection_keys]
["memory-protection-keys" : self.opts.pooling_memory_protection_keys]
enable => cfg.memory_protection_keys(if enable {
wasmtime::MpkEnabled::Enable
} else {
wasmtime::MpkEnabled::Disable
}),
_ => err,
}
match_feature! {
["memory-protection-keys" : self.opts.pooling_max_memory_protection_keys]
max => cfg.max_memory_protection_keys(max),
_ => err,
}
match_feature! {
["gc" : self.opts.pooling_total_gc_heaps]
max => cfg.total_gc_heaps(max),
_ => err,
}
config.allocation_strategy(wasmtime::InstanceAllocationStrategy::Pooling(cfg));
}
},
true => err,
}

if self.opts.memory_protection_keys.unwrap_or(false)
if self.opts.pooling_memory_protection_keys.unwrap_or(false)
&& !self.opts.pooling_allocator.unwrap_or(false)
{
anyhow::bail!("memory protection keys require the pooling allocator");
}

if self.opts.pooling_max_memory_protection_keys.is_some()
&& !self.opts.pooling_memory_protection_keys.unwrap_or(false)
{
anyhow::bail!(
"max memory protection keys requires memory protection keys to be enabled"
);
}

match_feature! {
["async" : self.wasm.async_stack_size]
size => config.async_stack_size(size),
Expand Down
103 changes: 69 additions & 34 deletions crates/cranelift/src/func_environ.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use cranelift_frontend::FunctionBuilder;
use cranelift_frontend::Variable;
use smallvec::SmallVec;
use std::mem;
use wasmparser::Operator;
use wasmparser::{Operator, WasmFeatures};
use wasmtime_environ::{
BuiltinFunctionIndex, DataIndex, ElemIndex, EngineOrModuleTypeIndex, FuncIndex, GlobalIndex,
IndexType, Memory, MemoryIndex, MemoryPlan, MemoryStyle, Module, ModuleInternedTypeIndex,
Expand Down Expand Up @@ -1304,13 +1304,15 @@ impl<'a, 'func, 'module_env> Call<'a, 'func, 'module_env> {
/// Do an indirect call through the given funcref table.
pub fn indirect_call(
mut self,
features: &WasmFeatures,
table_index: TableIndex,
ty_index: TypeIndex,
sig_ref: ir::SigRef,
callee: ir::Value,
call_args: &[ir::Value],
) -> WasmResult<Option<ir::Inst>> {
let (code_ptr, callee_vmctx) = match self.check_and_load_code_and_callee_vmctx(
features,
table_index,
ty_index,
callee,
Expand All @@ -1326,6 +1328,7 @@ impl<'a, 'func, 'module_env> Call<'a, 'func, 'module_env> {

fn check_and_load_code_and_callee_vmctx(
&mut self,
features: &WasmFeatures,
table_index: TableIndex,
ty_index: TypeIndex,
callee: ir::Value,
Expand All @@ -1343,7 +1346,8 @@ impl<'a, 'func, 'module_env> Call<'a, 'func, 'module_env> {
);

// If necessary, check the signature.
let check = self.check_indirect_call_type_signature(table_index, ty_index, funcref_ptr);
let check =
self.check_indirect_call_type_signature(features, table_index, ty_index, funcref_ptr);

let trap_code = match check {
// `funcref_ptr` is checked at runtime that its type matches,
Expand Down Expand Up @@ -1377,6 +1381,7 @@ impl<'a, 'func, 'module_env> Call<'a, 'func, 'module_env> {

fn check_indirect_call_type_signature(
&mut self,
features: &WasmFeatures,
table_index: TableIndex,
ty_index: TypeIndex,
funcref_ptr: ir::Value,
Expand Down Expand Up @@ -1412,33 +1417,40 @@ impl<'a, 'func, 'module_env> Call<'a, 'func, 'module_env> {
};
}

// Otherwise if the types don't match then either (a) this is a
// null pointer or (b) it's a pointer with the wrong type.
// Figure out which and trap here.
//
// If it's possible to have a null here then try to load the
// type information. If that fails due to the function being a
// null pointer, then this was a call to null. Otherwise if it
// succeeds then we know it won't match, so trap anyway.
if table.table.ref_type.nullable {
if self.env.signals_based_traps() {
let mem_flags = ir::MemFlags::trusted().with_readonly();
self.builder.ins().load(
sig_id_type,
mem_flags.with_trap_code(Some(crate::TRAP_INDIRECT_CALL_TO_NULL)),
funcref_ptr,
i32::from(self.env.offsets.ptr.vm_func_ref_type_index()),
);
} else {
self.env.trapz(
self.builder,
funcref_ptr,
crate::TRAP_INDIRECT_CALL_TO_NULL,
);
if features.gc() {
// If we are in the Wasm GC world, then we need to perform
// an actual subtype check at runtime. Fall through to below
// to do that.
} else {
// Otherwise if the types don't match then either (a) this
// is a null pointer or (b) it's a pointer with the wrong
// type. Figure out which and trap here.
//
// If it's possible to have a null here then try to load the
// type information. If that fails due to the function being
// a null pointer, then this was a call to null. Otherwise
// if it succeeds then we know it won't match, so trap
// anyway.
if table.table.ref_type.nullable {
if self.env.signals_based_traps() {
let mem_flags = ir::MemFlags::trusted().with_readonly();
self.builder.ins().load(
sig_id_type,
mem_flags.with_trap_code(Some(crate::TRAP_INDIRECT_CALL_TO_NULL)),
funcref_ptr,
i32::from(self.env.offsets.ptr.vm_func_ref_type_index()),
);
} else {
self.env.trapz(
self.builder,
funcref_ptr,
crate::TRAP_INDIRECT_CALL_TO_NULL,
);
}
}
self.env.trap(self.builder, crate::TRAP_BAD_SIGNATURE);
return CheckIndirectCallTypeSignature::StaticTrap;
}
self.env.trap(self.builder, crate::TRAP_BAD_SIGNATURE);
return CheckIndirectCallTypeSignature::StaticTrap;
}

// Tables of `nofunc` can only be inhabited by null, so go ahead and
Expand Down Expand Up @@ -1494,12 +1506,25 @@ impl<'a, 'func, 'module_env> Call<'a, 'func, 'module_env> {
self.env
.load_funcref_type_index(&mut self.builder.cursor(), mem_flags, funcref_ptr);

// Check that they match.
let cmp = self
.builder
.ins()
.icmp(IntCC::Equal, callee_sig_id, caller_sig_id);
self.env.trapz(self.builder, cmp, crate::TRAP_BAD_SIGNATURE);
// Check that they match: in the case of Wasm GC, this means doing a
// full subtype check. Otherwise, we do a simple equality check.
let matches = if features.gc() {
#[cfg(feature = "gc")]
{
self.env
.is_subtype(self.builder, callee_sig_id, caller_sig_id)
}
#[cfg(not(feature = "gc"))]
{
unreachable!()
}
} else {
self.builder
.ins()
.icmp(IntCC::Equal, callee_sig_id, caller_sig_id)
};
self.env
.trapz(self.builder, matches, crate::TRAP_BAD_SIGNATURE);
CheckIndirectCallTypeSignature::Runtime
}

Expand Down Expand Up @@ -2701,13 +2726,21 @@ impl<'module_environment> crate::translate::FuncEnvironment
fn translate_call_indirect(
&mut self,
builder: &mut FunctionBuilder,
features: &WasmFeatures,
table_index: TableIndex,
ty_index: TypeIndex,
sig_ref: ir::SigRef,
callee: ir::Value,
call_args: &[ir::Value],
) -> WasmResult<Option<ir::Inst>> {
Call::new(builder, self).indirect_call(table_index, ty_index, sig_ref, callee, call_args)
Call::new(builder, self).indirect_call(
features,
table_index,
ty_index,
sig_ref,
callee,
call_args,
)
}

fn translate_call(
Expand Down Expand Up @@ -2744,13 +2777,15 @@ impl<'module_environment> crate::translate::FuncEnvironment
fn translate_return_call_indirect(
&mut self,
builder: &mut FunctionBuilder,
features: &WasmFeatures,
table_index: TableIndex,
ty_index: TypeIndex,
sig_ref: ir::SigRef,
callee: ir::Value,
call_args: &[ir::Value],
) -> WasmResult<()> {
Call::new_tail(builder, self).indirect_call(
features,
table_index,
ty_index,
sig_ref,
Expand Down
2 changes: 2 additions & 0 deletions crates/cranelift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ pub const TRAP_CONTINUATION_ALREADY_CONSUMED: TrapCode =
TrapCode::unwrap_user(Trap::ContinuationAlreadyConsumed as u8 + TRAP_OFFSET);
pub const TRAP_DEBUG_ASSERTION: TrapCode =
TrapCode::unwrap_user(Trap::DebugAssertion as u8 + TRAP_OFFSET);
pub const TRAP_CAST_FAILURE: TrapCode =
TrapCode::unwrap_user(Trap::CastFailure as u8 + TRAP_OFFSET);

/// Creates a new cranelift `Signature` with no wasm params/results for the
/// given calling convention.
Expand Down
Loading