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:
@@ -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());
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user