Skip to content

Commit 9f6052d

Browse files
authored
Many more component OOM tests (#13088)
* Add OOM test for Component::serialize * Add OOM test for component Func::typed * Add OOM test for component Instance::get_export * Add OOM tests for component ResourceAny::try_from_resource and try_into_resource * Add OOM test for component Linker::define_unknown_imports_as_traps * Add OOM test for component LinkerInstance::func_wrap * Add OOM test for component LinkerInstance::func_new * Add OOM test for component LinkerInstance::module * Add OOM test for component LinkerInstance::resource * review feedback
1 parent 6dae01b commit 9f6052d

File tree

8 files changed

+308
-8
lines changed

8 files changed

+308
-8
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#![cfg(arc_try_new)]
2+
3+
use wasmtime::component::Component;
4+
use wasmtime::{Config, Engine, Result};
5+
use wasmtime_fuzzing::oom::OomTest;
6+
7+
#[test]
8+
fn component_serialize() -> 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+
(core module $m
18+
(func (export "id") (param i32) (result i32) (local.get 0))
19+
)
20+
(core instance $i (instantiate $m))
21+
(func (export "id") (param "x" s32) (result s32)
22+
(canon lift (core func $i "id"))
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+
35+
// Error propagation via anyhow allocates after OOM.
36+
OomTest::new().allow_alloc_after_oom(true).test(|| {
37+
let _bytes = component.serialize()?;
38+
Ok(())
39+
})
40+
}

crates/fuzzing/tests/oom/component_func.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,42 @@ fn component_typed_func_call() -> Result<()> {
246246
Ok(())
247247
})
248248
}
249+
250+
#[test]
251+
fn component_func_typed() -> Result<()> {
252+
let component_bytes = {
253+
let mut config = Config::new();
254+
config.concurrency_support(false);
255+
let engine = Engine::new(&config)?;
256+
Component::new(
257+
&engine,
258+
r#"
259+
(component
260+
(core module $m
261+
(func (export "id") (param i32) (result i32) (local.get 0))
262+
)
263+
(core instance $i (instantiate $m))
264+
(func (export "id") (param "x" s32) (result s32)
265+
(canon lift (core func $i "id"))
266+
)
267+
)
268+
"#,
269+
)?
270+
.serialize()?
271+
};
272+
let mut config = Config::new();
273+
config.enable_compiler(false);
274+
config.concurrency_support(false);
275+
let engine = Engine::new(&config)?;
276+
let component = unsafe { Component::deserialize(&engine, &component_bytes)? };
277+
let linker = Linker::<()>::new(&engine);
278+
let instance_pre = linker.instantiate_pre(&component)?;
279+
280+
OomTest::new().test(|| {
281+
let mut store = Store::try_new(&engine, ())?;
282+
let instance = instance_pre.instantiate(&mut store)?;
283+
let func = instance.get_func(&mut store, "id").unwrap();
284+
let _typed = func.typed::<(i32,), (i32,)>(&store)?;
285+
Ok(())
286+
})
287+
}

crates/fuzzing/tests/oom/component_instance.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,41 @@ fn instantiate_in_pooling_allocator() -> Result<()> {
4040
Ok(())
4141
})
4242
}
43+
44+
#[test]
45+
fn component_instance_get_export() -> Result<()> {
46+
let component_bytes = {
47+
let mut config = Config::new();
48+
config.concurrency_support(false);
49+
let engine = Engine::new(&config)?;
50+
Component::new(
51+
&engine,
52+
r#"
53+
(component
54+
(core module $m
55+
(func (export "id") (param i32) (result i32) (local.get 0))
56+
)
57+
(core instance $i (instantiate $m))
58+
(func (export "id") (param "x" s32) (result s32)
59+
(canon lift (core func $i "id"))
60+
)
61+
)
62+
"#,
63+
)?
64+
.serialize()?
65+
};
66+
let mut config = Config::new();
67+
config.enable_compiler(false);
68+
config.concurrency_support(false);
69+
let engine = Engine::new(&config)?;
70+
let component = unsafe { Component::deserialize(&engine, &component_bytes)? };
71+
let linker = Linker::<()>::new(&engine);
72+
let instance_pre = linker.instantiate_pre(&component)?;
73+
74+
OomTest::new().test(|| {
75+
let mut store = Store::try_new(&engine, ())?;
76+
let instance = instance_pre.instantiate(&mut store)?;
77+
let _export = instance.get_export(&mut store, None, "id");
78+
Ok(())
79+
})
80+
}

crates/fuzzing/tests/oom/component_linker.rs

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![cfg(arc_try_new)]
22

3-
use wasmtime::component::{Component, Linker};
4-
use wasmtime::{Config, Engine, Result, Store};
3+
use wasmtime::component::{Component, Linker, ResourceType};
4+
use wasmtime::{Config, Engine, Module, Result, Store};
55
use wasmtime_fuzzing::oom::OomTest;
66

77
#[tokio::test]
@@ -147,3 +147,103 @@ fn component_linker_substituted_component_type() -> Result<()> {
147147
Ok(())
148148
})
149149
}
150+
151+
#[test]
152+
fn component_linker_define_unknown_imports_as_traps() -> Result<()> {
153+
let component_bytes = {
154+
let mut config = Config::new();
155+
config.concurrency_support(false);
156+
let engine = Engine::new(&config)?;
157+
Component::new(
158+
&engine,
159+
r#"
160+
(component
161+
(import "f" (func))
162+
)
163+
"#,
164+
)?
165+
.serialize()?
166+
};
167+
let mut config = Config::new();
168+
config.enable_compiler(false);
169+
config.concurrency_support(false);
170+
let engine = Engine::new(&config)?;
171+
let component = unsafe { Component::deserialize(&engine, &component_bytes)? };
172+
173+
// Error propagation via anyhow allocates after OOM.
174+
OomTest::new().allow_alloc_after_oom(true).test(|| {
175+
let mut linker = Linker::<()>::new(&engine);
176+
linker.define_unknown_imports_as_traps(&component)?;
177+
Ok(())
178+
})
179+
}
180+
181+
#[test]
182+
fn component_linker_instance_func_wrap() -> Result<()> {
183+
let mut config = Config::new();
184+
config.concurrency_support(false);
185+
let engine = Engine::new(&config)?;
186+
187+
// Error propagation via anyhow allocates after OOM.
188+
OomTest::new().allow_alloc_after_oom(true).test(|| {
189+
let mut linker = Linker::<()>::new(&engine);
190+
linker
191+
.root()
192+
.func_wrap("f", |_cx: wasmtime::StoreContextMut<'_, ()>, (): ()| Ok(()))?;
193+
Ok(())
194+
})
195+
}
196+
197+
#[test]
198+
fn component_linker_instance_func_new() -> Result<()> {
199+
let mut config = Config::new();
200+
config.concurrency_support(false);
201+
let engine = Engine::new(&config)?;
202+
203+
// Error propagation via anyhow allocates after OOM.
204+
OomTest::new().allow_alloc_after_oom(true).test(|| {
205+
let mut linker = Linker::<()>::new(&engine);
206+
linker
207+
.root()
208+
.func_new("f", |_cx, _func_ty, _params, _results| Ok(()))?;
209+
Ok(())
210+
})
211+
}
212+
213+
#[test]
214+
fn component_linker_instance_module() -> Result<()> {
215+
let module_bytes = {
216+
let mut config = Config::new();
217+
config.concurrency_support(false);
218+
let engine = Engine::new(&config)?;
219+
Module::new(&engine, "(module)")?.serialize()?
220+
};
221+
let mut config = Config::new();
222+
config.enable_compiler(false);
223+
config.concurrency_support(false);
224+
let engine = Engine::new(&config)?;
225+
let module = unsafe { Module::deserialize(&engine, &module_bytes)? };
226+
227+
// Error propagation via anyhow allocates after OOM.
228+
OomTest::new().allow_alloc_after_oom(true).test(|| {
229+
let mut linker = Linker::<()>::new(&engine);
230+
linker.root().module("m", &module)?;
231+
Ok(())
232+
})
233+
}
234+
235+
#[test]
236+
fn component_linker_instance_resource() -> Result<()> {
237+
let mut config = Config::new();
238+
config.concurrency_support(false);
239+
let engine = Engine::new(&config)?;
240+
241+
// Error propagation from HostFunc::wrap allocates via anyhow.
242+
OomTest::new().allow_alloc_after_oom(true).test(|| {
243+
let mut linker = Linker::<()>::new(&engine);
244+
linker
245+
.root()
246+
.resource("r", ResourceType::host::<()>(), |_, _| Ok(()))?;
247+
Ok(())
248+
})
249+
}

crates/fuzzing/tests/oom/component_resource.rs

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![cfg(arc_try_new)]
22

3-
use wasmtime::component::{Component, Linker, ResourceAny};
3+
use wasmtime::component::{Component, Linker, Resource, ResourceAny, ResourceType};
44
use wasmtime::{Config, Engine, Result, Store};
55
use wasmtime_fuzzing::oom::OomTest;
66

@@ -87,3 +87,81 @@ fn component_resource_any_resource_drop() -> Result<()> {
8787
Ok(())
8888
})
8989
}
90+
91+
struct MyResource;
92+
93+
#[test]
94+
fn component_resource_any_try_from_resource() -> Result<()> {
95+
let component_bytes = {
96+
let mut config = Config::new();
97+
config.concurrency_support(false);
98+
let engine = Engine::new(&config)?;
99+
Component::new(
100+
&engine,
101+
r#"
102+
(component
103+
(import "t" (type $t (sub resource)))
104+
)
105+
"#,
106+
)?
107+
.serialize()?
108+
};
109+
let mut config = Config::new();
110+
config.enable_compiler(false);
111+
config.concurrency_support(false);
112+
let engine = Engine::new(&config)?;
113+
let component = unsafe { Component::deserialize(&engine, &component_bytes)? };
114+
let mut linker = Linker::<()>::new(&engine);
115+
linker
116+
.root()
117+
.resource("t", ResourceType::host::<MyResource>(), |_, _| Ok(()))?;
118+
let instance_pre = linker.instantiate_pre(&component)?;
119+
120+
// Error propagation via anyhow allocates after OOM.
121+
OomTest::new().allow_alloc_after_oom(true).test(|| {
122+
let mut store = Store::try_new(&engine, ())?;
123+
let _instance = instance_pre.instantiate(&mut store)?;
124+
let resource = Resource::<MyResource>::new_own(42);
125+
let any = ResourceAny::try_from_resource(resource, &mut store)?;
126+
let _typed: Resource<MyResource> = any.try_into_resource(&mut store)?;
127+
Ok(())
128+
})
129+
}
130+
131+
#[test]
132+
fn component_resource_any_try_into_resource() -> Result<()> {
133+
let component_bytes = {
134+
let mut config = Config::new();
135+
config.concurrency_support(false);
136+
let engine = Engine::new(&config)?;
137+
Component::new(
138+
&engine,
139+
r#"
140+
(component
141+
(import "t" (type $t (sub resource)))
142+
)
143+
"#,
144+
)?
145+
.serialize()?
146+
};
147+
let mut config = Config::new();
148+
config.enable_compiler(false);
149+
config.concurrency_support(false);
150+
let engine = Engine::new(&config)?;
151+
let component = unsafe { Component::deserialize(&engine, &component_bytes)? };
152+
let mut linker = Linker::<()>::new(&engine);
153+
linker
154+
.root()
155+
.resource("t", ResourceType::host::<MyResource>(), |_, _| Ok(()))?;
156+
let instance_pre = linker.instantiate_pre(&component)?;
157+
158+
// Error propagation via anyhow allocates after OOM.
159+
OomTest::new().allow_alloc_after_oom(true).test(|| {
160+
let mut store = Store::try_new(&engine, ())?;
161+
let _instance = instance_pre.instantiate(&mut store)?;
162+
let resource = Resource::<MyResource>::new_own(100);
163+
let any = ResourceAny::try_from_resource(resource, &mut store)?;
164+
let _back: Resource<MyResource> = any.try_into_resource(&mut store)?;
165+
Ok(())
166+
})
167+
}

crates/fuzzing/tests/oom/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod bit_set;
55
mod boxed;
66
mod btree_map;
77
mod caller;
8+
mod component_component;
89
mod component_func;
910
mod component_instance;
1011
mod component_linker;

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,11 @@ impl Component {
592592
/// [`Module::serialize`]: crate::Module::serialize
593593
/// [`Module`]: crate::Module
594594
pub fn serialize(&self) -> Result<Vec<u8>> {
595-
Ok(self.engine_code().image().to_vec())
595+
let image = self.engine_code().image();
596+
let mut v = TryVec::new();
597+
v.reserve(image.len())?;
598+
v.try_extend(image.iter().copied())?;
599+
Ok(v.into())
596600
}
597601

598602
/// Creates a new `VMFuncRef` with all fields filled out for the destructor

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -757,10 +757,10 @@ impl<T: 'static> LinkerInstance<'_, T> {
757757
ty: ResourceType,
758758
dtor: impl Fn(StoreContextMut<'_, T>, u32) -> Result<()> + Send + Sync + 'static,
759759
) -> Result<()> {
760-
let dtor = Arc::new(crate::func::HostFunc::wrap(
760+
let dtor = try_new::<Arc<_>>(crate::func::HostFunc::wrap(
761761
&self.engine,
762762
move |mut cx: crate::Caller<'_, T>, (param,): (u32,)| dtor(cx.as_context_mut(), param),
763-
)?);
763+
)?)?;
764764
self.insert(name, Definition::Resource(ty, dtor))?;
765765
Ok(())
766766
}
@@ -775,10 +775,10 @@ impl<T: 'static> LinkerInstance<'_, T> {
775775
+ Sync
776776
+ 'static,
777777
{
778-
let dtor = Arc::new(crate::func::HostFunc::wrap_async(
778+
let dtor = try_new::<Arc<_>>(crate::func::HostFunc::wrap_async(
779779
&self.engine,
780780
move |cx: crate::Caller<'_, T>, (param,): (u32,)| dtor(cx.into(), param),
781-
)?);
781+
)?)?;
782782
self.insert(name, Definition::Resource(ty, dtor))?;
783783
Ok(())
784784
}

0 commit comments

Comments
 (0)