Skip to content

Commit b2fd5de

Browse files
authored
Add OOM test for component ResourceAny::resource_drop_async (#13051)
Convert several infallible allocations to fallible alternatives: - HandleTable::slots: Vec<Slot> -> TryVec<Slot> - HostResourceData::table_slot_metadata: Vec<TableSlot> -> TryVec<TableSlot> - Resource type tracking: PrimaryMap<ResourceIndex, ResourceType> -> TryPrimaryMap across vm/component.rs, instance.rs, matching.rs, types.rs, component.rs, and linker.rs - Backtrace trace_through_continuations: remove Vec::collect() calls, iterate directly to avoid allocation - catch_traps: Box::new(Trap) -> try_new::<Box<_>>(Trap)
1 parent 0b9b7bd commit b2fd5de

File tree

12 files changed

+108
-68
lines changed

12 files changed

+108
-68
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#![cfg(arc_try_new)]
2+
3+
use wasmtime::component::{Component, Linker, ResourceAny};
4+
use wasmtime::{Config, Engine, Result, Store};
5+
use wasmtime_fuzzing::oom::OomTest;
6+
7+
#[tokio::test]
8+
async fn component_resource_any_resource_drop_async() -> Result<()> {
9+
let component_bytes = {
10+
let mut config = Config::new();
11+
config.concurrency_support(false);
12+
let engine = Engine::new(&config)?;
13+
Component::new(
14+
&engine,
15+
r#"
16+
(component
17+
(type $t' (resource (rep i32)))
18+
(export $t "t" (type $t'))
19+
20+
(core func $new (canon resource.new $t))
21+
(func (export "mk") (param "r" u32) (result (own $t))
22+
(canon lift (core func $new))
23+
)
24+
)
25+
"#,
26+
)?
27+
.serialize()?
28+
};
29+
let mut config = Config::new();
30+
config.enable_compiler(false);
31+
config.concurrency_support(false);
32+
let engine = Engine::new(&config)?;
33+
let component = unsafe { Component::deserialize(&engine, &component_bytes)? };
34+
let linker = Linker::<()>::new(&engine);
35+
let instance_pre = linker.instantiate_pre(&component)?;
36+
37+
OomTest::new()
38+
.allow_alloc_after_oom(true)
39+
.test_async(|| async {
40+
let mut store = Store::try_new(&engine, ())?;
41+
let instance = instance_pre.instantiate_async(&mut store).await?;
42+
let mk = instance.get_typed_func::<(u32,), (ResourceAny,)>(&mut store, "mk")?;
43+
let (resource,) = mk.call_async(&mut store, (42,)).await?;
44+
resource.resource_drop_async(&mut store).await?;
45+
Ok(())
46+
})
47+
.await
48+
}

crates/fuzzing/tests/oom/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod btree_map;
77
mod caller;
88
mod component_func;
99
mod component_linker;
10+
mod component_resource;
1011
mod config;
1112
mod engine;
1213
mod entity_set;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ impl Component {
388388
}
389389

390390
fn with_uninstantiated_instance_type<R>(&self, f: impl FnOnce(&InstanceType<'_>) -> R) -> R {
391-
let resources = Arc::new(PrimaryMap::new());
391+
let resources = Arc::new(TryPrimaryMap::new());
392392
f(&InstanceType {
393393
types: self.types(),
394394
resources: &resources,

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,7 @@ pub(crate) enum RuntimeImport {
715715
},
716716
}
717717

718-
pub type ImportedResources = PrimaryMap<ResourceIndex, ResourceType>;
718+
pub type ImportedResources = TryPrimaryMap<ResourceIndex, ResourceType>;
719719

720720
impl<'a> Instantiator<'a> {
721721
fn new(
@@ -727,7 +727,7 @@ impl<'a> Instantiator<'a> {
727727
let (modules, engine, breakpoints) = store.modules_and_engine_and_breakpoints_mut();
728728
modules.register_component(component, engine, breakpoints)?;
729729
let imported_resources: ImportedResources =
730-
PrimaryMap::with_capacity(env_component.imported_resources.len());
730+
TryPrimaryMap::with_capacity(env_component.imported_resources.len())?;
731731

732732
let instance = ComponentInstance::new(
733733
store.store_data().components.next_component_instance_id(),
@@ -763,7 +763,7 @@ impl<'a> Instantiator<'a> {
763763
} => (*ty, NonNull::from(dtor_funcref)),
764764
_ => unreachable!(),
765765
};
766-
let i = self.instance_resource_types_mut(store.0).push(ty);
766+
let i = self.instance_resource_types_mut(store.0).push(ty)?;
767767
assert_eq!(i, idx);
768768
self.instance_mut(store.0)
769769
.set_resource_destructor(idx, Some(func_ref));
@@ -906,13 +906,13 @@ impl<'a> Instantiator<'a> {
906906
self.extract_post_return(store.0, post_return)
907907
}
908908

909-
GlobalInitializer::Resource(r) => self.resource(store.0, r),
909+
GlobalInitializer::Resource(r) => self.resource(store.0, r)?,
910910
}
911911
}
912912
Ok(())
913913
}
914914

915-
fn resource(&mut self, store: &mut StoreOpaque, resource: &Resource) {
915+
fn resource(&mut self, store: &mut StoreOpaque, resource: &Resource) -> Result<()> {
916916
let dtor = resource
917917
.dtor
918918
.as_ref()
@@ -929,8 +929,9 @@ impl<'a> Instantiator<'a> {
929929
let ty = ResourceType::guest(store.id(), instance, resource.index);
930930
self.instance_mut(store)
931931
.set_resource_destructor(index, dtor);
932-
let i = self.instance_resource_types_mut(store).push(ty);
932+
let i = self.instance_resource_types_mut(store).push(ty)?;
933933
debug_assert_eq!(i, index);
934+
Ok(())
934935
}
935936

936937
fn extract_memory(&mut self, store: &mut StoreOpaque, memory: &ExtractMemory) {
@@ -1088,7 +1089,7 @@ impl<'a> Instantiator<'a> {
10881089
pub struct InstancePre<T: 'static> {
10891090
component: Component,
10901091
imports: Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
1091-
resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
1092+
resource_types: Arc<TryPrimaryMap<ResourceIndex, ResourceType>>,
10921093
asyncness: Asyncness,
10931094
_marker: marker::PhantomData<fn() -> T>,
10941095
}
@@ -1116,7 +1117,7 @@ impl<T: 'static> InstancePre<T> {
11161117
pub(crate) unsafe fn new_unchecked(
11171118
component: Component,
11181119
imports: Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
1119-
resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
1120+
resource_types: Arc<TryPrimaryMap<ResourceIndex, ResourceType>>,
11201121
) -> InstancePre<T> {
11211122
let mut asyncness = Asyncness::No;
11221123
for (_, import) in imports.iter() {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ impl<T: 'static> Linker<T> {
177177
engine: &self.engine,
178178
types: component.types(),
179179
strings: &self.strings,
180-
imported_resources: try_new::<Arc<_>>(Default::default())?,
180+
imported_resources: try_new::<Arc<_>>(TryPrimaryMap::new())?,
181181
};
182182

183183
// Walk over the component's list of import names and use that to lookup

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,25 @@ use crate::runtime::vm::component::ComponentInstance;
77
use crate::types::matching;
88
use crate::{Engine, prelude::*};
99
use alloc::sync::Arc;
10-
use wasmtime_environ::PrimaryMap;
1110
use wasmtime_environ::component::{
1211
ComponentTypes, NameMap, ResourceIndex, TypeComponentInstance, TypeDef, TypeFuncIndex,
1312
TypeFutureTableIndex, TypeModule, TypeResourceTable, TypeResourceTableIndex,
1413
TypeStreamTableIndex,
1514
};
15+
use wasmtime_environ::prelude::TryPrimaryMap;
1616

1717
pub struct TypeChecker<'a> {
1818
pub engine: &'a Engine,
1919
pub types: &'a Arc<ComponentTypes>,
2020
pub strings: &'a Strings,
21-
pub imported_resources: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
21+
pub imported_resources: Arc<TryPrimaryMap<ResourceIndex, ResourceType>>,
2222
}
2323

2424
#[derive(Copy, Clone)]
2525
#[doc(hidden)]
2626
pub struct InstanceType<'a> {
2727
pub types: &'a Arc<ComponentTypes>,
28-
pub resources: &'a Arc<PrimaryMap<ResourceIndex, ResourceType>>,
28+
pub resources: &'a Arc<TryPrimaryMap<ResourceIndex, ResourceType>>,
2929
}
3030

3131
impl TypeChecker<'_> {
@@ -89,7 +89,7 @@ impl TypeChecker<'_> {
8989
// cloned.
9090
None => {
9191
let resources = Arc::get_mut(&mut self.imported_resources).unwrap();
92-
let id = resources.push(*actual);
92+
let id = resources.push(*actual)?;
9393
assert_eq!(id, i);
9494
}
9595

crates/wasmtime/src/runtime/component/resources/host_tables.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ pub struct HostResourceTables<'a> {
6262
#[derive(Default)]
6363
pub struct HostResourceData {
6464
cur_generation: u32,
65-
table_slot_metadata: Vec<TableSlot>,
65+
table_slot_metadata: TryVec<TableSlot>,
6666
}
6767

6868
#[derive(Copy, Clone)]
@@ -145,15 +145,15 @@ impl<'a> HostResourceTables<'a> {
145145
instance: Option<RuntimeInstance>,
146146
) -> Result<HostResourceIndex> {
147147
let idx = self.tables.resource_lower_own(TypedResource::Host(rep))?;
148-
Ok(self.new_host_index(idx, dtor, instance))
148+
Ok(self.new_host_index(idx, dtor, instance)?)
149149
}
150150

151151
/// See [`HostResourceTables::host_resource_lower_own`].
152152
pub fn host_resource_lower_borrow(&mut self, rep: u32) -> Result<HostResourceIndex> {
153153
let idx = self
154154
.tables
155155
.resource_lower_borrow(TypedResource::Host(rep))?;
156-
Ok(self.new_host_index(idx, None, None))
156+
Ok(self.new_host_index(idx, None, None)?)
157157
}
158158

159159
/// Validates that `idx` is still valid for the host tables, notably
@@ -201,7 +201,7 @@ impl<'a> HostResourceTables<'a> {
201201
idx: u32,
202202
dtor: Option<NonNull<VMFuncRef>>,
203203
instance: Option<RuntimeInstance>,
204-
) -> HostResourceIndex {
204+
) -> Result<HostResourceIndex> {
205205
let list = &mut self.host_resource_data.table_slot_metadata;
206206
let info = TableSlot {
207207
generation: self.host_resource_data.cur_generation,
@@ -219,14 +219,14 @@ impl<'a> HostResourceTables<'a> {
219219
generation: 0,
220220
instance: None,
221221
dtor: None,
222-
});
222+
})?;
223223
}
224224
assert_eq!(idx as usize, list.len());
225-
list.push(info);
225+
list.push(info)?;
226226
}
227227
}
228228

229-
HostResourceIndex::new(idx, info.generation)
229+
Ok(HostResourceIndex::new(idx, info.generation))
230230
}
231231

232232
/// Drops a host-owned resource from host tables.

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ use crate::{Engine, ExternType, FuncType, prelude::*};
77
use alloc::sync::Arc;
88
use core::fmt;
99
use core::ops::Deref;
10+
use wasmtime_environ::PanicOnOom as _;
1011
use wasmtime_environ::component::{
1112
ComponentTypes, Export, InterfaceType, ResourceIndex, TypeComponentIndex,
1213
TypeComponentInstanceIndex, TypeDef, TypeEnumIndex, TypeFlagsIndex, TypeFuncIndex,
1314
TypeFutureIndex, TypeFutureTableIndex, TypeListIndex, TypeMapIndex, TypeModuleIndex,
1415
TypeOptionIndex, TypeRecordIndex, TypeResourceTable, TypeResourceTableIndex, TypeResultIndex,
1516
TypeStreamIndex, TypeStreamTableIndex, TypeTupleIndex, TypeVariantIndex,
1617
};
17-
use wasmtime_environ::{PanicOnOom as _, PrimaryMap};
1818

1919
pub use crate::component::resources::ResourceType;
2020

@@ -40,7 +40,7 @@ pub use crate::component::resources::ResourceType;
4040
struct Handle<T> {
4141
index: T,
4242
types: Arc<ComponentTypes>,
43-
resources: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
43+
resources: Arc<TryPrimaryMap<ResourceIndex, ResourceType>>,
4444
}
4545

4646
impl<T> Handle<T> {
@@ -94,9 +94,9 @@ impl<T: fmt::Debug> fmt::Debug for Handle<T> {
9494
/// Type checker between two `Handle`s
9595
struct TypeChecker<'a> {
9696
a_types: &'a ComponentTypes,
97-
a_resource: &'a PrimaryMap<ResourceIndex, ResourceType>,
97+
a_resource: &'a TryPrimaryMap<ResourceIndex, ResourceType>,
9898
b_types: &'a ComponentTypes,
99-
b_resource: &'a PrimaryMap<ResourceIndex, ResourceType>,
99+
b_resource: &'a TryPrimaryMap<ResourceIndex, ResourceType>,
100100
}
101101

102102
impl TypeChecker<'_> {

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ pub struct ComponentInstance {
138138

139139
/// Storage for the type information about resources within this component
140140
/// instance.
141-
resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
141+
resource_types: Arc<TryPrimaryMap<ResourceIndex, ResourceType>>,
142142

143143
/// Arguments that this instance used to be instantiated.
144144
///
@@ -319,7 +319,7 @@ impl ComponentInstance {
319319
pub(crate) fn new(
320320
id: ComponentInstanceId,
321321
component: &Component,
322-
resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
322+
resource_types: Arc<TryPrimaryMap<ResourceIndex, ResourceType>>,
323323
imports: &Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
324324
store: NonNull<dyn VMStore>,
325325
) -> Result<OwnedComponentInstance, OutOfMemory> {
@@ -826,14 +826,14 @@ impl ComponentInstance {
826826
}
827827

828828
/// Returns a reference to the resource type information.
829-
pub fn resource_types(&self) -> &Arc<PrimaryMap<ResourceIndex, ResourceType>> {
829+
pub fn resource_types(&self) -> &Arc<TryPrimaryMap<ResourceIndex, ResourceType>> {
830830
&self.resource_types
831831
}
832832

833833
/// Returns a mutable reference to the resource type information.
834834
pub fn resource_types_mut(
835835
self: Pin<&mut Self>,
836-
) -> &mut Arc<PrimaryMap<ResourceIndex, ResourceType>> {
836+
) -> &mut Arc<TryPrimaryMap<ResourceIndex, ResourceType>> {
837837
// SAFETY: we've chosen the `Pin` guarantee of `Self` to not apply to
838838
// the map returned.
839839
unsafe { &mut self.get_unchecked_mut().resource_types }

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::{TypedResource, TypedResourceIndex};
2+
use crate::prelude::TryVec;
23
use crate::{Result, bail};
3-
use alloc::vec::Vec;
44
use core::mem;
55
use wasmtime_environ::component::{TypeFutureTableIndex, TypeStreamTableIndex};
66

@@ -114,14 +114,14 @@ enum Slot {
114114

115115
pub struct HandleTable {
116116
next: u32,
117-
slots: Vec<Slot>,
117+
slots: TryVec<Slot>,
118118
}
119119

120120
impl Default for HandleTable {
121121
fn default() -> Self {
122122
Self {
123123
next: 0,
124-
slots: Vec::new(),
124+
slots: TryVec::new(),
125125
}
126126
}
127127
}
@@ -139,7 +139,7 @@ impl HandleTable {
139139
if next == self.slots.len() {
140140
self.slots.push(Slot::Free {
141141
next: self.next.checked_add(1).unwrap(),
142-
});
142+
})?;
143143
}
144144
let ret = self.next;
145145
self.next = match mem::replace(&mut self.slots[next], slot) {

0 commit comments

Comments
 (0)