Revamp memory management of InstanceHandle (#1624)

* 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
This commit is contained in:
Alex Crichton
2020-04-29 12:47:49 -05:00
committed by GitHub
parent 738e2742da
commit 654e953fbf
21 changed files with 315 additions and 256 deletions

View File

@@ -204,21 +204,11 @@ impl CompiledModule {
/// See `InstanceHandle::new`
pub unsafe fn instantiate(
&self,
is_bulk_memory: bool,
resolver: &mut dyn Resolver,
sig_registry: &SignatureRegistry,
mem_creator: Option<&dyn RuntimeMemoryCreator>,
max_wasm_stack: usize,
host_state: Box<dyn Any>,
) -> Result<InstanceHandle, InstantiationError> {
let data_initializers = self
.data_initializers
.iter()
.map(|init| DataInitializer {
location: init.location.clone(),
data: &*init.data,
})
.collect::<Vec<_>>();
let imports = resolve_imports(&self.module, &sig_registry, resolver)?;
InstanceHandle::new(
Arc::clone(&self.module),
@@ -226,16 +216,24 @@ impl CompiledModule {
self.trampolines.clone(),
imports,
mem_creator,
&data_initializers,
self.signatures.clone(),
self.dbg_jit_registration.as_ref().map(|r| Rc::clone(&r)),
is_bulk_memory,
host_state,
self.interrupts.clone(),
max_wasm_stack,
)
}
/// Returns data initializers to pass to `InstanceHandle::initialize`
pub fn data_initializers(&self) -> Vec<DataInitializer<'_>> {
self.data_initializers
.iter()
.map(|init| DataInitializer {
location: init.location.clone(),
data: &*init.data,
})
.collect()
}
/// Return a reference-counting pointer to a module.
pub fn module(&self) -> &Arc<Module> {
&self.module