* Revamp memory management of `InstanceHandle` This commit fixes a known but in Wasmtime where an instance could still be used after it was freed. Unfortunately the fix here is a bit of a hammer, but it's the best that we can do for now. The changes made in this commit are: * A `Store` now stores all `InstanceHandle` objects it ever creates. This keeps all instances alive unconditionally (along with all host functions and such) until the `Store` is itself dropped. Note that a `Store` is reference counted so basically everything has to be dropped to drop anything, there's no longer any partial deallocation of instances. * The `InstanceHandle` type's own reference counting has been removed. This is largely redundant with what's already happening in `Store`, so there's no need to manage two reference counts. * Each `InstanceHandle` no longer tracks its dependencies in terms of instance handles. This set was actually inaccurate due to dynamic updates to tables and such, so we needed to revamp it anyway. * Initialization of an `InstanceHandle` is now deferred until after `InstanceHandle::new`. This allows storing the `InstanceHandle` before side-effectful initialization, such as copying element segments or running the start function, to ensure that regardless of the result of instantiation the underlying `InstanceHandle` is still available to persist in storage. Overall this should fix a known possible way to safely segfault Wasmtime today (yay!) and it should also fix some flaikness I've seen on CI. Turns out one of the spec tests (bulk-memory-operations/partial-init-table-segment.wast) exercises this functionality and we were hitting sporating use-after-free, but only on Windows. * Shuffle some APIs around * Comment weak cycle
47 lines
1.7 KiB
Rust
47 lines
1.7 KiB
Rust
use crate::vmcontext::{VMFunctionImport, VMGlobalImport, VMMemoryImport, VMTableImport};
|
|
use wasmtime_environ::entity::{BoxedSlice, PrimaryMap};
|
|
use wasmtime_environ::wasm::{FuncIndex, GlobalIndex, MemoryIndex, TableIndex};
|
|
|
|
/// Resolved import pointers.
|
|
#[derive(Clone)]
|
|
pub struct Imports {
|
|
/// Resolved addresses for imported functions.
|
|
pub functions: BoxedSlice<FuncIndex, VMFunctionImport>,
|
|
|
|
/// Resolved addresses for imported tables.
|
|
pub tables: BoxedSlice<TableIndex, VMTableImport>,
|
|
|
|
/// Resolved addresses for imported memories.
|
|
pub memories: BoxedSlice<MemoryIndex, VMMemoryImport>,
|
|
|
|
/// Resolved addresses for imported globals.
|
|
pub globals: BoxedSlice<GlobalIndex, VMGlobalImport>,
|
|
}
|
|
|
|
impl Imports {
|
|
/// Construct a new `Imports` instance.
|
|
pub fn new(
|
|
function_imports: PrimaryMap<FuncIndex, VMFunctionImport>,
|
|
table_imports: PrimaryMap<TableIndex, VMTableImport>,
|
|
memory_imports: PrimaryMap<MemoryIndex, VMMemoryImport>,
|
|
global_imports: PrimaryMap<GlobalIndex, VMGlobalImport>,
|
|
) -> Self {
|
|
Self {
|
|
functions: function_imports.into_boxed_slice(),
|
|
tables: table_imports.into_boxed_slice(),
|
|
memories: memory_imports.into_boxed_slice(),
|
|
globals: global_imports.into_boxed_slice(),
|
|
}
|
|
}
|
|
|
|
/// Construct a new `Imports` instance with no imports.
|
|
pub fn none() -> Self {
|
|
Self {
|
|
functions: PrimaryMap::new().into_boxed_slice(),
|
|
tables: PrimaryMap::new().into_boxed_slice(),
|
|
memories: PrimaryMap::new().into_boxed_slice(),
|
|
globals: PrimaryMap::new().into_boxed_slice(),
|
|
}
|
|
}
|
|
}
|