Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit 0f958c9

Browse files
committed
fix memory leak when panicking with detached ComponentInstance
In `ComponentInstance::from_vmctx` and `StoreContextMut::with_detached_instance[_async]` we were leaking memory due to having taken `InstanceData` out of the `Store` and making it unreachable except via a raw pointer, meaning there was nothing responsible for dropping it on panic. This commit adds an RAII wrapper to take care of that. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
1 parent 90e7e16 commit 0f958c9

2 files changed

Lines changed: 37 additions & 19 deletions

File tree

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

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,14 @@ impl fmt::Debug for WorkItem {
685685
}
686686
}
687687

688+
struct DataDropper<'a>(&'a mut ComponentInstance);
689+
690+
impl Drop for DataDropper<'_> {
691+
fn drop(&mut self) {
692+
drop(self.0.data.take());
693+
}
694+
}
695+
688696
impl<T> StoreContextMut<'_, T> {
689697
/// Temporarily split the specified store and instance into a "detached"
690698
/// state (i.e. clearing the pointers they have to each other) so that they
@@ -721,11 +729,12 @@ impl<T> StoreContextMut<'_, T> {
721729
// it and can take an exclusive reference to it.
722730
let instance = unsafe { &mut *data.instance_ptr() };
723731
assert!(instance.data.is_none());
724-
instance.data = Some(data);
725-
instance.set_store(None);
726-
let result = fun(self.as_context_mut(), instance);
727-
instance.set_store(Some(VMStoreRawPtr(self.traitobj())));
728-
(result, instance.data.take())
732+
let instance = DataDropper(instance);
733+
instance.0.data = Some(data);
734+
instance.0.set_store(None);
735+
let result = fun(self.as_context_mut(), instance.0);
736+
instance.0.set_store(Some(VMStoreRawPtr(self.traitobj())));
737+
(result, instance.0.data.take())
729738
};
730739
if self.0[instance.0].is_none() {
731740
self.0[instance.0] = data;
@@ -753,10 +762,11 @@ impl<T> StoreContextMut<'_, T> {
753762
let instance = unsafe { &mut *data.instance_ptr() };
754763
assert!(instance.data.is_none());
755764
instance.data = Some(data);
756-
instance.set_store(None);
757-
let result = fun(self.as_context_mut(), instance).await;
758-
instance.set_store(Some(VMStoreRawPtr(self.traitobj())));
759-
(result, instance.data.take())
765+
let instance = DataDropper(instance);
766+
instance.0.set_store(None);
767+
let result = fun(self.as_context_mut(), instance.0).await;
768+
instance.0.set_store(Some(VMStoreRawPtr(self.traitobj())));
769+
(result, instance.0.data.take())
760770
};
761771
if self.0[instance.0].is_none() {
762772
self.0[instance.0] = data;

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

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -183,21 +183,29 @@ impl ComponentInstance {
183183
vmctx: NonNull<VMComponentContext>,
184184
f: impl FnOnce(&mut dyn VMStore, &mut ComponentInstance) -> R,
185185
) -> R {
186+
struct DataDropper<'a>(&'a mut ComponentInstance);
187+
188+
impl Drop for DataDropper<'_> {
189+
fn drop(&mut self) {
190+
drop(self.0.data.take());
191+
}
192+
}
193+
186194
let mut ptr = vmctx
187195
.byte_sub(mem::size_of::<ComponentInstance>())
188196
.cast::<ComponentInstance>();
189-
let reference = ptr.as_mut();
190-
let store = &mut *reference.store();
191-
if let Some(instance) = reference.instance {
192-
assert!(reference.data.is_none());
193-
reference.data = Some(store[instance.0].take().unwrap());
197+
let reference = DataDropper(ptr.as_mut());
198+
let store = &mut *reference.0.store();
199+
if let Some(instance) = reference.0.instance {
200+
assert!(reference.0.data.is_none());
201+
reference.0.data = Some(store[instance.0].take().unwrap());
194202
}
195-
reference.set_store(None);
196-
let result = f(store, reference);
197-
reference.set_store(Some(VMStoreRawPtr(store.traitobj())));
198-
if let Some(instance) = reference.instance {
203+
reference.0.set_store(None);
204+
let result = f(store, reference.0);
205+
reference.0.set_store(Some(VMStoreRawPtr(store.traitobj())));
206+
if let Some(instance) = reference.0.instance {
199207
if store[instance.0].is_none() {
200-
store[instance.0] = reference.data.take();
208+
store[instance.0] = reference.0.data.take();
201209
}
202210
}
203211
result

0 commit comments

Comments
 (0)