Skip to content

Commit 3c04e0a

Browse files
alexcrichtonbongjunj
authored andcommitted
Delete StoreOpaque::traitobj_mut (bytecodealliance#11444)
* Delete `StoreOpaque::traitobj_mut` This was a fundamentally unsound function because it is widening a mutable borrow to encompass more than it originally contained. Removal of its usage falls into a few buckets here: * Many instances of `store.0.traitobj_mut()` were starting from a `&mut StoreInner<T>`, going to `&mut StoreOpaque`, then going back to `&mut dyn VMStore`. These are replaced with `store.0` as `&mut StoreInner<T>` directly coerces into `&mut dyn VMStore`. * Some fiber-related helpers were updated to take any store-opaque-thing which encapsulates the ability to start/resume a borrow with a part of the store, but you only get that part of the store during the fiber itself. This means there's no widening necessary. * Some methods previously taking `&mut StoreOpaque` are now appropriately widened to `&mut dyn VMStore`. This all enables full deletion of this function which prevents accidentally ever tripping over its unsound-ness. * Fix configured build * Another fix for a configured build * Fix a warning * Don't hold `VMStore` live over await points * Review comments * Move `AsStoreOpaque` to `store.rs` and use it in GC * Fix configured build * Switch lint annotation
1 parent 715d439 commit 3c04e0a

9 files changed

Lines changed: 117 additions & 126 deletions

File tree

crates/wasmtime/src/runtime/component/concurrent.rs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,7 +1088,7 @@ impl Instance {
10881088

10891089
impl<'a, T, V> Drop for Dropper<'a, T, V> {
10901090
fn drop(&mut self) {
1091-
tls::set(self.store.0.traitobj_mut(), || {
1091+
tls::set(self.store.0, || {
10921092
// SAFETY: Here we drop the value without moving it for the
10931093
// first and only time -- per the contract for `Drop::drop`,
10941094
// this code won't run again, and the `value` field will no
@@ -1163,7 +1163,7 @@ impl Instance {
11631163
/// can be made (in which case we trap with `Trap::AsyncDeadlock`).
11641164
async fn poll_until<T, R>(
11651165
self,
1166-
store: StoreContextMut<'_, T>,
1166+
mut store: StoreContextMut<'_, T>,
11671167
mut future: Pin<&mut impl Future<Output = R>>,
11681168
) -> Result<R> {
11691169
loop {
@@ -1312,19 +1312,23 @@ impl Instance {
13121312
// any work items and then loop again.
13131313
Either::Right(ready) => {
13141314
for item in ready {
1315-
self.handle_work_item(store.0.traitobj_mut(), item).await?;
1315+
self.handle_work_item(store.as_context_mut(), item).await?;
13161316
}
13171317
}
13181318
}
13191319
}
13201320
}
13211321

13221322
/// Handle the specified work item, possibly resuming a fiber if applicable.
1323-
async fn handle_work_item(self, store: &mut StoreOpaque, item: WorkItem) -> Result<()> {
1323+
async fn handle_work_item<T>(
1324+
self,
1325+
store: StoreContextMut<'_, T>,
1326+
item: WorkItem,
1327+
) -> Result<()> {
13241328
log::trace!("handle work item {item:?}");
13251329
match item {
13261330
WorkItem::PushFuture(future) => {
1327-
self.concurrent_state_mut(store)
1331+
self.concurrent_state_mut(store.0)
13281332
.futures
13291333
.get_mut()
13301334
.unwrap()
@@ -1333,10 +1337,10 @@ impl Instance {
13331337
.push(future.into_inner().unwrap());
13341338
}
13351339
WorkItem::ResumeFiber(fiber) => {
1336-
self.resume_fiber(store, fiber).await?;
1340+
self.resume_fiber(store.0, fiber).await?;
13371341
}
13381342
WorkItem::GuestCall(call) => {
1339-
let state = self.concurrent_state_mut(store);
1343+
let state = self.concurrent_state_mut(store.0);
13401344
if call.is_ready(state)? {
13411345
self.run_on_worker(store, WorkerItem::GuestCall(call))
13421346
.await?;
@@ -1362,7 +1366,7 @@ impl Instance {
13621366
}
13631367
}
13641368
WorkItem::Poll(params) => {
1365-
let state = self.concurrent_state_mut(store);
1369+
let state = self.concurrent_state_mut(store.0);
13661370
if state.get_mut(params.task)?.event.is_some()
13671371
|| !state.get_mut(params.set)?.ready.is_empty()
13681372
{
@@ -1434,11 +1438,11 @@ impl Instance {
14341438
}
14351439

14361440
/// Execute the specified guest call on a worker fiber.
1437-
async fn run_on_worker(self, store: &mut StoreOpaque, item: WorkerItem) -> Result<()> {
1438-
let worker = if let Some(fiber) = self.concurrent_state_mut(store).worker.take() {
1441+
async fn run_on_worker<T>(self, store: StoreContextMut<'_, T>, item: WorkerItem) -> Result<()> {
1442+
let worker = if let Some(fiber) = self.concurrent_state_mut(store.0).worker.take() {
14391443
fiber
14401444
} else {
1441-
fiber::make_fiber(store.traitobj_mut(), move |store| {
1445+
fiber::make_fiber(store.0, move |store| {
14421446
loop {
14431447
match self.concurrent_state_mut(store).worker_item.take().unwrap() {
14441448
WorkerItem::GuestCall(call) => self.handle_guest_call(store, call)?,
@@ -1450,11 +1454,11 @@ impl Instance {
14501454
})?
14511455
};
14521456

1453-
let worker_item = &mut self.concurrent_state_mut(store).worker_item;
1457+
let worker_item = &mut self.concurrent_state_mut(store.0).worker_item;
14541458
assert!(worker_item.is_none());
14551459
*worker_item = Some(item);
14561460

1457-
self.resume_fiber(store, worker).await
1461+
self.resume_fiber(store.0, worker).await
14581462
}
14591463

14601464
/// Execute the specified guest call.
@@ -1531,7 +1535,7 @@ impl Instance {
15311535
};
15321536

15331537
let old_guest_task = if let Some(task) = task {
1534-
self.maybe_pop_call_context(store.store_opaque_mut(), task)?;
1538+
self.maybe_pop_call_context(store, task)?;
15351539
self.concurrent_state_mut(store).guest_task
15361540
} else {
15371541
None
@@ -1545,7 +1549,7 @@ impl Instance {
15451549

15461550
if let Some(task) = task {
15471551
self.concurrent_state_mut(store).guest_task = old_guest_task;
1548-
self.maybe_push_call_context(store.store_opaque_mut(), task)?;
1552+
self.maybe_push_call_context(store, task)?;
15491553
}
15501554

15511555
Ok(())
@@ -2217,10 +2221,7 @@ impl Instance {
22172221
// before committing to such an optimization. And again, we'd need to
22182222
// update the spec to allow that.
22192223
let (status, waitable) = loop {
2220-
self.suspend(
2221-
store.0.traitobj_mut(),
2222-
SuspendReason::Waiting { set, task: caller },
2223-
)?;
2224+
self.suspend(store.0, SuspendReason::Waiting { set, task: caller })?;
22242225

22252226
let state = self.concurrent_state_mut(store.0);
22262227

@@ -2414,7 +2415,7 @@ impl Instance {
24142415
Poll::Ready(output) => {
24152416
// It finished immediately; lower the result and delete the
24162417
// task.
2417-
output.consume(store.0.traitobj_mut(), self)?;
2418+
output.consume(store.0, self)?;
24182419
log::trace!("delete host task {task:?} (already ready)");
24192420
self.concurrent_state_mut(store.0).delete(task)?;
24202421
None

crates/wasmtime/src/runtime/component/concurrent/futures_and_streams.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -680,11 +680,7 @@ impl<T> FutureReader<T> {
680680
// `self` should never be used again, but leave an invalid handle there just in case.
681681
let id = mem::replace(&mut self.id, TableId::new(0));
682682
self.instance
683-
.host_drop_reader(
684-
store.as_context_mut().0.traitobj_mut(),
685-
id,
686-
TransmitKind::Future,
687-
)
683+
.host_drop_reader(store.as_context_mut().0, id, TransmitKind::Future)
688684
.unwrap();
689685
}
690686

@@ -1252,11 +1248,7 @@ impl<T> StreamReader<T> {
12521248
// `self` should never be used again, but leave an invalid handle there just in case.
12531249
let id = mem::replace(&mut self.id, TableId::new(0));
12541250
self.instance
1255-
.host_drop_reader(
1256-
store.as_context_mut().0.traitobj_mut(),
1257-
id,
1258-
TransmitKind::Stream,
1259-
)
1251+
.host_drop_reader(store.as_context_mut().0, id, TransmitKind::Stream)
12601252
.unwrap()
12611253
}
12621254

@@ -2047,7 +2039,7 @@ impl Instance {
20472039

20482040
WriteState::HostReady { accept, post_write } => {
20492041
accept(
2050-
store.0.traitobj_mut(),
2042+
store.0,
20512043
self,
20522044
Reader::Host {
20532045
accept: Box::new(|input, count| {
@@ -2863,7 +2855,7 @@ impl Instance {
28632855
}
28642856

28652857
let code = accept(
2866-
store.0.traitobj_mut(),
2858+
store.0,
28672859
self,
28682860
Reader::Guest {
28692861
options: &options,

crates/wasmtime/src/runtime/component/func/host.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ where
344344
HostResult::Done(result) => result?,
345345
#[cfg(feature = "component-model-async")]
346346
HostResult::Future(future) => {
347-
instance.poll_and_block(store.0.traitobj_mut(), future, caller_instance)?
347+
instance.poll_and_block(store.0, future, caller_instance)?
348348
}
349349
};
350350

@@ -826,8 +826,7 @@ where
826826
params_and_results,
827827
result_start,
828828
);
829-
let result_vals =
830-
instance.poll_and_block(store.0.traitobj_mut(), future, caller_instance)?;
829+
let result_vals = instance.poll_and_block(store.0, future, caller_instance)?;
831830
let result_vals = &result_vals[result_start..];
832831

833832
unsafe {

crates/wasmtime/src/runtime/component/linker.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,7 @@ impl<T: 'static> LinkerInstance<'_, T> {
837837
);
838838
let mut future = std::pin::pin!(dtor(accessor, param));
839839
std::future::poll_fn(|cx| {
840-
crate::component::concurrent::tls::set(store.0.traitobj_mut(), || {
840+
crate::component::concurrent::tls::set(store.0, || {
841841
future.as_mut().poll(cx)
842842
})
843843
})

crates/wasmtime/src/runtime/component/store.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#[cfg(feature = "component-model-async")]
2+
use crate::runtime::vm::VMStore;
13
use crate::runtime::vm::component::{ComponentInstance, OwnedComponentInstance};
24
use crate::store::{StoreData, StoreId, StoreOpaque};
35
#[cfg(feature = "component-model-async")]
@@ -32,7 +34,7 @@ impl ComponentStoreData {
3234
}
3335

3436
#[cfg(feature = "component-model-async")]
35-
pub(crate) fn drop_fibers_and_futures(store: &mut StoreOpaque) {
37+
pub(crate) fn drop_fibers_and_futures(store: &mut dyn VMStore) {
3638
let mut fibers = Vec::new();
3739
let mut futures = Vec::new();
3840
for (_, instance) in store.store_data_mut().components.instances.iter_mut() {
@@ -50,7 +52,7 @@ impl ComponentStoreData {
5052
fiber.dispose(store);
5153
}
5254

53-
crate::component::concurrent::tls::set(store.traitobj_mut(), move || drop(futures));
55+
crate::component::concurrent::tls::set(store, move || drop(futures));
5456
}
5557
}
5658

crates/wasmtime/src/runtime/fiber.rs

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::prelude::*;
2-
use crate::store::{Executor, StoreId, StoreInner, StoreOpaque};
2+
use crate::store::{AsStoreOpaque, Executor, StoreId, StoreOpaque};
33
use crate::vm::mpk::{self, ProtectionMask};
4-
use crate::vm::{AlwaysMut, AsyncWasmCallState, VMStore};
4+
use crate::vm::{AlwaysMut, AsyncWasmCallState};
55
use crate::{Engine, StoreContextMut};
66
use anyhow::{Result, anyhow};
77
use core::mem;
@@ -113,22 +113,6 @@ impl AsyncState {
113113
}
114114
}
115115

116-
trait AsStoreOpaque {
117-
fn as_store_opaque(&mut self) -> &mut StoreOpaque;
118-
}
119-
120-
impl AsStoreOpaque for StoreOpaque {
121-
fn as_store_opaque(&mut self) -> &mut StoreOpaque {
122-
self
123-
}
124-
}
125-
126-
impl<T: 'static> AsStoreOpaque for StoreInner<T> {
127-
fn as_store_opaque(&mut self) -> &mut StoreOpaque {
128-
self
129-
}
130-
}
131-
132116
/// A helper structure used to block a fiber.
133117
///
134118
/// This is acquired via either `StoreContextMut::with_blocking` or
@@ -785,15 +769,19 @@ fn resume_fiber<'a>(
785769
}
786770

787771
/// Create a new `StoreFiber` which runs the specified closure.
788-
pub(crate) fn make_fiber<'a>(
789-
store: &mut dyn VMStore,
790-
fun: impl FnOnce(&mut dyn VMStore) -> Result<()> + Send + Sync + 'a,
791-
) -> Result<StoreFiber<'a>> {
792-
let engine = store.engine().clone();
772+
pub(crate) fn make_fiber<'a, S>(
773+
store: &mut S,
774+
fun: impl FnOnce(&mut S) -> Result<()> + Send + Sync + 'a,
775+
) -> Result<StoreFiber<'a>>
776+
where
777+
S: AsStoreOpaque + ?Sized + 'a,
778+
{
779+
let opaque = store.as_store_opaque();
780+
let engine = opaque.engine().clone();
793781
let executor = Executor::new(&engine);
794-
let id = store.store_opaque().id();
795-
let stack = store.store_opaque_mut().allocate_fiber_stack()?;
796-
let track_pkey_context_switch = store.has_pkey();
782+
let id = opaque.id();
783+
let stack = opaque.allocate_fiber_stack()?;
784+
let track_pkey_context_switch = opaque.has_pkey();
797785
let store = &raw mut *store;
798786
let fiber = Fiber::new(stack, move |result: WasmtimeResume, suspend| {
799787
let future_cx = match result {
@@ -812,17 +800,22 @@ pub(crate) fn make_fiber<'a>(
812800
// the fiber is running and `future_cx` and `suspend` are both in scope.
813801
// Note that these pointers are removed when this function returns as
814802
// that's when they fall out of scope.
815-
let async_state = store_ref.store_opaque_mut().fiber_async_state_mut();
803+
let async_state = store_ref.as_store_opaque().fiber_async_state_mut();
816804
assert!(async_state.current_suspend.is_none());
817805
assert!(async_state.current_future_cx.is_none());
818806
async_state.current_suspend = Some(NonNull::from(suspend));
819807
async_state.current_future_cx = Some(future_cx);
820808

821-
struct ResetCurrentPointersToNull<'a>(&'a mut dyn VMStore);
809+
struct ResetCurrentPointersToNull<'a, S>(&'a mut S)
810+
where
811+
S: AsStoreOpaque + ?Sized;
822812

823-
impl Drop for ResetCurrentPointersToNull<'_> {
813+
impl<S> Drop for ResetCurrentPointersToNull<'_, S>
814+
where
815+
S: AsStoreOpaque + ?Sized,
816+
{
824817
fn drop(&mut self) {
825-
let state = self.0.fiber_async_state_mut();
818+
let state = self.0.as_store_opaque().fiber_async_state_mut();
826819

827820
// Double-check that the current suspension isn't null (it
828821
// should be what's in this closure). Note though that we
@@ -861,23 +854,28 @@ pub(crate) fn make_fiber<'a>(
861854

862855
/// Run the specified function on a newly-created fiber and `.await` its
863856
/// completion.
864-
pub(crate) async fn on_fiber<R: Send + Sync>(
865-
store: &mut StoreOpaque,
866-
func: impl FnOnce(&mut StoreOpaque) -> R + Send + Sync,
867-
) -> Result<R> {
868-
let config = store.engine().config();
869-
debug_assert!(store.async_support());
857+
pub(crate) async fn on_fiber<S, R>(
858+
store: &mut S,
859+
func: impl FnOnce(&mut S) -> R + Send + Sync,
860+
) -> Result<R>
861+
where
862+
S: AsStoreOpaque + ?Sized,
863+
R: Send + Sync,
864+
{
865+
let opaque = store.as_store_opaque();
866+
let config = opaque.engine().config();
867+
debug_assert!(opaque.async_support());
870868
debug_assert!(config.async_stack_size > 0);
871869

872870
let mut result = None;
873-
let fiber = make_fiber(store.traitobj_mut(), |store| {
871+
let fiber = make_fiber(store, |store| {
874872
result = Some(func(store));
875873
Ok(())
876874
})?;
877875

878876
{
879877
let fiber = FiberFuture {
880-
store,
878+
store: store.as_store_opaque(),
881879
fiber: Some(fiber),
882880
#[cfg(feature = "component-model-async")]
883881
on_release: OnRelease::ReturnPending,

0 commit comments

Comments
 (0)