externref: implement a canary for GC stack walking

This allows us to detect when stack walking has failed to walk the whole stack,
and we are potentially missing on-stack roots, and therefore it would be unsafe
to do a GC because we could free objects too early, leading to use-after-free.
When we detect this scenario, we skip the GC.
This commit is contained in:
Nick Fitzgerald
2020-06-11 14:29:30 -07:00
parent f30ce1fe97
commit 618c278e41
3 changed files with 195 additions and 26 deletions

View File

@@ -194,9 +194,17 @@ macro_rules! getters {
>(export.address);
let mut ret = None;
$(let $args = $args.into_abi();)*
catch_traps(export.vmctx, &instance.store, || {
ret = Some(fnptr(export.vmctx, ptr::null_mut(), $($args,)*));
})?;
{
let canary = 0;
let _auto_reset = instance
.store
.externref_activations_table()
.set_stack_canary(&canary);
catch_traps(export.vmctx, &instance.store, || {
ret = Some(fnptr(export.vmctx, ptr::null_mut(), $($args,)*));
})?;
}
Ok(ret.unwrap())
}
@@ -552,14 +560,23 @@ impl Func {
}
// Call the trampoline.
catch_traps(self.export.vmctx, &self.instance.store, || unsafe {
(self.trampoline)(
self.export.vmctx,
ptr::null_mut(),
self.export.address,
values_vec.as_mut_ptr(),
)
})?;
{
let canary = 0;
let _auto_reset = self
.instance
.store
.externref_activations_table()
.set_stack_canary(&canary);
catch_traps(self.export.vmctx, &self.instance.store, || unsafe {
(self.trampoline)(
self.export.vmctx,
ptr::null_mut(),
self.export.address,
values_vec.as_mut_ptr(),
)
})?;
}
// Load the return values out of `values_vec`.
let mut results = Vec::with_capacity(my_ty.results().len());

View File

@@ -1097,10 +1097,14 @@ impl Store {
/// Perform garbage collection of `ExternRef`s.
pub fn gc(&self) {
wasmtime_runtime::gc(
&*self.inner.stack_map_registry,
&*self.inner.externref_activations_table,
);
// For this crate's API, we ensure that `set_stack_canary` invariants
// are upheld for all host-->Wasm calls.
unsafe {
wasmtime_runtime::gc(
&*self.inner.stack_map_registry,
&*self.inner.externref_activations_table,
);
}
}
}