Skip to content

Commit 26993da

Browse files
authored
Introduce a Vec<T> collection that forces fallible allocation (#12440)
* Introduce a `Vec<T>` collection that forces fallible allocation Part of #12069 * review feedback
1 parent 7dbcf4c commit 26993da

3 files changed

Lines changed: 170 additions & 0 deletions

File tree

crates/environ/src/collections.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
33
mod entity_set;
44
mod primary_map;
5+
mod vec;
56

67
pub use entity_set::EntitySet;
78
pub use primary_map::PrimaryMap;
9+
pub use vec::Vec;
810
pub use wasmtime_core::alloc::{TryNew, try_new};
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
use crate::error::OutOfMemory;
2+
use alloc::vec::Vec as StdVec;
3+
use core::{
4+
fmt,
5+
ops::{Deref, DerefMut, Index, IndexMut},
6+
};
7+
8+
/// Like `std::vec::Vec` but all methods that allocate force handling allocation
9+
/// failure.
10+
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
11+
pub struct Vec<T> {
12+
inner: StdVec<T>,
13+
}
14+
15+
impl<T> Default for Vec<T> {
16+
fn default() -> Self {
17+
Self {
18+
inner: Default::default(),
19+
}
20+
}
21+
}
22+
23+
impl<T: fmt::Debug> fmt::Debug for Vec<T> {
24+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25+
fmt::Debug::fmt(&self.inner, f)
26+
}
27+
}
28+
29+
impl<T> Vec<T> {
30+
/// Same as [`std::vec::Vec::new`].
31+
pub fn new() -> Self {
32+
Default::default()
33+
}
34+
35+
/// Same as [`std::vec::Vec::with_capacity`] but returns an error on
36+
/// allocation failure.
37+
pub fn with_capacity(capacity: usize) -> Result<Self, OutOfMemory> {
38+
let mut v = Self::new();
39+
v.reserve(capacity)?;
40+
Ok(v)
41+
}
42+
43+
/// Same as [`std::vec::Vec::reserve`] but returns an error on allocation
44+
/// failure.
45+
pub fn reserve(&mut self, additional: usize) -> Result<(), OutOfMemory> {
46+
self.inner.try_reserve(additional).map_err(|_| {
47+
OutOfMemory::new(
48+
self.len()
49+
.saturating_add(additional)
50+
.saturating_mul(core::mem::size_of::<T>()),
51+
)
52+
})
53+
}
54+
55+
/// Same as [`std::vec::Vec::reserve_exact`] but returns an error on allocation
56+
/// failure.
57+
pub fn reserve_exact(&mut self, additional: usize) -> Result<(), OutOfMemory> {
58+
self.inner
59+
.try_reserve_exact(additional)
60+
.map_err(|_| OutOfMemory::new(self.len().saturating_add(additional)))
61+
}
62+
63+
/// Same as [`std::vec::Vec::len`].
64+
pub fn len(&self) -> usize {
65+
self.inner.len()
66+
}
67+
68+
/// Same as [`std::vec::Vec::capacity`].
69+
pub fn capacity(&self) -> usize {
70+
self.inner.capacity()
71+
}
72+
73+
/// Same as [`std::vec::Vec::is_empty`].
74+
pub fn is_empty(&self) -> bool {
75+
self.inner.is_empty()
76+
}
77+
78+
/// Same as [`std::vec::Vec::push`] but returns an error on allocation
79+
/// failure.
80+
pub fn push(&mut self, value: T) -> Result<(), OutOfMemory> {
81+
self.reserve(1)?;
82+
self.inner.push(value);
83+
Ok(())
84+
}
85+
}
86+
87+
impl<T> Deref for Vec<T> {
88+
type Target = [T];
89+
90+
fn deref(&self) -> &Self::Target {
91+
&self.inner
92+
}
93+
}
94+
95+
impl<T> DerefMut for Vec<T> {
96+
fn deref_mut(&mut self) -> &mut Self::Target {
97+
&mut self.inner
98+
}
99+
}
100+
101+
impl<T> Index<usize> for Vec<T> {
102+
type Output = T;
103+
104+
fn index(&self, index: usize) -> &Self::Output {
105+
&self.inner[index]
106+
}
107+
}
108+
109+
impl<T> IndexMut<usize> for Vec<T> {
110+
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
111+
&mut self.inner[index]
112+
}
113+
}
114+
115+
impl<'a, T> IntoIterator for &'a Vec<T> {
116+
type Item = &'a T;
117+
118+
type IntoIter = core::slice::Iter<'a, T>;
119+
120+
fn into_iter(self) -> Self::IntoIter {
121+
(**self).iter()
122+
}
123+
}
124+
125+
impl<'a, T> IntoIterator for &'a mut Vec<T> {
126+
type Item = &'a mut T;
127+
128+
type IntoIter = core::slice::IterMut<'a, T>;
129+
130+
fn into_iter(self) -> Self::IntoIter {
131+
(**self).iter_mut()
132+
}
133+
}

crates/fuzzing/tests/oom.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,41 @@ fn primary_map_try_reserve_exact() -> Result<()> {
106106
})
107107
}
108108

109+
#[test]
110+
fn vec_with_capacity() -> Result<()> {
111+
OomTest::new().test(|| {
112+
let _v = wasmtime_environ::collections::Vec::<usize>::with_capacity(100)?;
113+
Ok(())
114+
})
115+
}
116+
117+
#[test]
118+
fn vec_reserve() -> Result<()> {
119+
OomTest::new().test(|| {
120+
let mut v = wasmtime_environ::collections::Vec::<usize>::new();
121+
v.reserve(10)?;
122+
Ok(())
123+
})
124+
}
125+
126+
#[test]
127+
fn vec_reserve_exact() -> Result<()> {
128+
OomTest::new().test(|| {
129+
let mut v = wasmtime_environ::collections::Vec::<usize>::new();
130+
v.reserve_exact(3)?;
131+
Ok(())
132+
})
133+
}
134+
135+
#[test]
136+
fn vec_push() -> Result<()> {
137+
OomTest::new().test(|| {
138+
let mut v = wasmtime_environ::collections::Vec::new();
139+
v.push(42)?;
140+
Ok(())
141+
})
142+
}
143+
109144
#[test]
110145
fn config_new() -> Result<()> {
111146
OomTest::new().test(|| {

0 commit comments

Comments
 (0)