Skip to content

Commit d856258

Browse files
committed
rust: add fallible allocation methods
These are all fallible alternatives to all currently used methods that may perform infallible allocation. `assume_fallible` is a semantically marker function to denote that we have proved that the closure passed to it will not perform infallible allocation. Signed-off-by: Gary Guo <[email protected]>
1 parent 7884043 commit d856258

File tree

5 files changed

+112
-8
lines changed

5 files changed

+112
-8
lines changed

rust/kernel/io_buffer.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
//! Buffers used in IO.
44
5+
use crate::traits::VecExt;
56
use crate::Result;
67
use alloc::vec::Vec;
78
use core::mem::{size_of, MaybeUninit};
@@ -29,9 +30,8 @@ pub trait IoBufferReader {
2930
///
3031
/// Returns `EFAULT` if the address does not currently point to mapped, readable memory.
3132
fn read_all(&mut self) -> Result<Vec<u8>> {
32-
let mut data = Vec::<u8>::new();
33-
data.try_reserve_exact(self.len())?;
34-
data.resize(self.len(), 0);
33+
let mut data = Vec::try_with_capacity(self.len())?;
34+
data.try_resize(self.len(), 0)?;
3535

3636
// SAFETY: The output buffer is valid as we just allocated it.
3737
unsafe { self.read_raw(data.as_mut_ptr(), data.len())? };

rust/kernel/module_param.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h)
66
77
use crate::str::CStr;
8+
use crate::traits::TryToOwned;
89
use core::fmt::Write;
910

1011
/// Types that can be used for module parameters.
@@ -475,9 +476,7 @@ impl ModuleParam for StringParam {
475476
let slab_available = unsafe { crate::bindings::slab_is_available() };
476477
arg.and_then(|arg| {
477478
if slab_available {
478-
let mut vec = alloc::vec::Vec::new();
479-
vec.try_reserve_exact(arg.len()).ok()?;
480-
vec.extend_from_slice(arg);
479+
let vec = arg.try_to_owned().ok()?;
481480
Some(StringParam::Owned(vec))
482481
} else {
483482
Some(StringParam::Ref(arg))

rust/kernel/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ pub use super::static_assert;
2323

2424
pub use super::{KernelModule, Result};
2525

26-
pub use crate::traits::TryPin;
26+
pub use crate::traits::{TryPin, TryToOwned, VecExt as _};

rust/kernel/traits.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,19 @@
44
55
use core::{ops::Deref, pin::Pin};
66

7+
use alloc::collections::TryReserveError;
8+
use alloc::string::String;
9+
use alloc::vec::Vec;
710
use alloc::{alloc::AllocError, sync::Arc};
811

12+
type AllocResult<T = ()> = core::result::Result<T, AllocError>;
13+
type CollectionResult<T = ()> = core::result::Result<T, TryReserveError>;
14+
15+
#[inline]
16+
fn assume_fallible<T, F: FnOnce() -> T>(f: F) -> T {
17+
f()
18+
}
19+
920
/// Trait which provides a fallible version of `pin()` for pointer types.
1021
///
1122
/// Common pointer types which implement a `pin()` method include [`Box`](alloc::boxed::Box) and [`Arc`].
@@ -24,3 +35,97 @@ impl<T> TryPin<Arc<T>> for Arc<T> {
2435
Ok(unsafe { Pin::new_unchecked(Arc::try_new(data)?) })
2536
}
2637
}
38+
39+
pub trait TryToOwned {
40+
type Owned: core::borrow::Borrow<Self>;
41+
42+
#[must_use = "cloning is often expensive and is not expected to have side effects"]
43+
fn try_to_owned(&self) -> AllocResult<Self::Owned>;
44+
45+
fn try_clone_into(&self, target: &mut Self::Owned) -> AllocResult {
46+
*target = self.try_to_owned()?;
47+
Ok(())
48+
}
49+
}
50+
51+
impl<T: Clone> TryToOwned for [T] {
52+
type Owned = Vec<T>;
53+
54+
fn try_to_owned(&self) -> AllocResult<Vec<T>> {
55+
let mut vec = Vec::new();
56+
self.try_clone_into(&mut vec)?;
57+
Ok(vec)
58+
}
59+
60+
fn try_clone_into(&self, target: &mut Vec<T>) -> AllocResult {
61+
// Ensure target has enough capacity
62+
target
63+
.try_reserve_exact(self.len().saturating_sub(target.len()))
64+
.map_err(|_| AllocError)?;
65+
66+
target.clear();
67+
assume_fallible(|| target.extend_from_slice(self));
68+
Ok(())
69+
}
70+
}
71+
72+
impl TryToOwned for str {
73+
type Owned = String;
74+
75+
fn try_to_owned(&self) -> AllocResult<String> {
76+
let mut vec = String::new();
77+
self.try_clone_into(&mut vec)?;
78+
Ok(vec)
79+
}
80+
81+
fn try_clone_into(&self, target: &mut String) -> AllocResult {
82+
// Ensure target has enough capacity
83+
target
84+
.try_reserve_exact(self.len().saturating_sub(target.len()))
85+
.map_err(|_| AllocError)?;
86+
87+
target.clear();
88+
assume_fallible(|| target.push_str(self));
89+
Ok(())
90+
}
91+
}
92+
93+
pub trait VecExt<T> {
94+
fn try_with_capacity(capacity: usize) -> CollectionResult<Self>
95+
where
96+
Self: Sized;
97+
98+
fn try_extend_from_slice(&mut self, other: &[T]) -> CollectionResult
99+
where
100+
T: Clone;
101+
102+
fn try_resize(&mut self, new_len: usize, value: T) -> CollectionResult
103+
where
104+
T: Clone;
105+
}
106+
107+
impl<T> VecExt<T> for alloc::vec::Vec<T> {
108+
fn try_with_capacity(capacity: usize) -> CollectionResult<Self> {
109+
let mut vec = Self::new();
110+
vec.try_reserve_exact(capacity)?;
111+
Ok(vec)
112+
}
113+
114+
fn try_extend_from_slice(&mut self, other: &[T]) -> CollectionResult
115+
where
116+
T: Clone,
117+
{
118+
self.try_reserve(other.len())?;
119+
assume_fallible(|| self.extend_from_slice(other));
120+
Ok(())
121+
}
122+
123+
fn try_resize(&mut self, new_len: usize, value: T) -> CollectionResult
124+
where
125+
T: Clone,
126+
{
127+
self.try_reserve(new_len.saturating_sub(self.len()))?;
128+
assume_fallible(|| self.resize(new_len, value));
129+
Ok(())
130+
}
131+
}

samples/rust/rust_minimal.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl KernelModule for RustMinimal {
2525
pr_info!("Am I built-in? {}\n", !cfg!(MODULE));
2626

2727
Ok(RustMinimal {
28-
message: "on the heap!".to_owned(),
28+
message: "on the heap!".try_to_owned()?,
2929
})
3030
}
3131
}

0 commit comments

Comments
 (0)