safe_transmute/guard.rs
1//! The `guard` module exposes an API for memory boundary checking.
2//!
3//! # Examples:
4//!
5//! In order to check whether a value would fit in the given
6//! slice with no extra trailing bytes:
7//!
8//! ```
9//! # use safe_transmute::error::GuardError;
10//! # use safe_transmute::guard::{SingleValueGuard, Guard};
11//! # fn run() -> Result<(), GuardError> {
12//! SingleValueGuard::check::<u32>(&[0x00, 0x01, 0x00, 0x02])?;
13//! # Ok(())
14//! # }
15//! # run().unwrap();
16//! ```
17//!
18//! Different guard types implement different checking strategies.
19//! For example, the pedantic guard type [`PedanticGuard`](struct.PedanticGuard.html) requires
20//! the slice to have space for at least one value, and not have
21//! extraneous bytes at the end.
22//!
23//! ```
24//! # use safe_transmute::error::GuardError;
25//! # use safe_transmute::guard::{PedanticGuard, Guard};
26//! # fn run() -> Result<(), GuardError> {
27//! PedanticGuard::check::<u16>(&[0xAA, 0xAA, 0xBB, 0xBB, 0xCC, 0xCC])?;
28//! # Ok(())
29//! # }
30//! # run().unwrap();
31//! ```
32//!
33//! [`PermissiveGuard`](struct.PermissiveGuard.html), on the other hand, will accept any memory slice.
34//!
35//! ```
36//! # use safe_transmute::error::GuardError;
37//! # use safe_transmute::guard::{PermissiveGuard, Guard};
38//! # fn run() -> Result<(), GuardError> {
39//! PermissiveGuard::check::<i16>(b"covfefe")?;
40//! # Ok(())
41//! # }
42//! # run().unwrap();
43//! ```
44//!
45//! If the check fails, the resulting [`GuardError`](../type.GuardError.html) value describes why.
46//!
47//! ```
48//! # use safe_transmute::{GuardError, ErrorReason};
49//! # use safe_transmute::guard::{PedanticGuard, Guard};
50//! assert_eq!(PedanticGuard::check::<i16>(b"covfefe"),
51//! Err(GuardError {
52//! required: 2,
53//! actual: 7,
54//! reason: ErrorReason::InexactByteCount,
55//! }));
56//! ```
57//!
58//! # Note
59//!
60//! Regardless of the chosen strategy, guarded transmutation functions will
61//! always ensure that no out of bounds access is attempted. All functions will
62//! restrict the output to spatially safe portions of the input. The guard
63//! API exists to establish expectations in the conversion process.
64
65
66use error::{ErrorReason, GuardError};
67use core::mem::size_of;
68
69
70/// The trait describes types which define boundary checking strategies.
71/// See the [module-level documentation](index.html) for more details.
72pub trait Guard {
73 /// Check the size of the given byte slice against a particular type.
74 ///
75 /// # Errors
76 ///
77 /// If the slice's size does not comply with this guard, an error
78 /// which specifies the incompatibility is returned.
79 fn check<T>(v: &[u8]) -> Result<(), GuardError>;
80}
81
82
83/// Single value guard: The byte slice must have exactly enough bytes to fill a single
84/// instance of a type.
85pub struct SingleValueGuard;
86
87impl Guard for SingleValueGuard {
88 fn check<T>(bytes: &[u8]) -> Result<(), GuardError> {
89 if bytes.len() != size_of::<T>() {
90 Err(GuardError {
91 required: size_of::<T>(),
92 actual: bytes.len(),
93 reason: ErrorReason::InexactByteCount,
94 })
95 } else {
96 Ok(())
97 }
98 }
99}
100
101
102/// Pedantic guard: The byte slice must have at least enough bytes to fill a single
103/// instance of a type, and should not have extraneous data.
104pub struct PedanticGuard;
105
106impl Guard for PedanticGuard {
107 fn check<T>(bytes: &[u8]) -> Result<(), GuardError> {
108 if bytes.len() < size_of::<T>() {
109 Err(GuardError {
110 required: size_of::<T>(),
111 actual: bytes.len(),
112 reason: ErrorReason::NotEnoughBytes,
113 })
114 } else if (size_of::<T>() == 0 && bytes.len() != 0) || (size_of::<T>() != 0 && bytes.len() % size_of::<T>() != 0) {
115 Err(GuardError {
116 required: size_of::<T>(),
117 actual: bytes.len(),
118 reason: ErrorReason::InexactByteCount,
119 })
120 } else {
121 Ok(())
122 }
123 }
124}
125
126
127/// An all-or-nothing guard: The byte slice should not have extraneous data, but can be
128/// empty, unlike `PedanticGuard`.
129pub struct AllOrNothingGuard;
130
131impl Guard for AllOrNothingGuard {
132 fn check<T>(bytes: &[u8]) -> Result<(), GuardError> {
133 if (size_of::<T>() == 0 && bytes.len() != 0) || (size_of::<T>() != 0 && bytes.len() % size_of::<T>() != 0) {
134 Err(GuardError {
135 required: size_of::<T>(),
136 actual: bytes.len(),
137 reason: ErrorReason::InexactByteCount,
138 })
139 } else {
140 Ok(())
141 }
142 }
143}
144
145
146/// A single-or-many guard: The byte slice must have at least enough bytes to fill a single
147/// instance of a type, and extraneous data is ignored.
148pub struct SingleManyGuard;
149
150impl Guard for SingleManyGuard {
151 fn check<T>(bytes: &[u8]) -> Result<(), GuardError> {
152 if bytes.len() < size_of::<T>() {
153 Err(GuardError {
154 required: size_of::<T>(),
155 actual: bytes.len(),
156 reason: ErrorReason::NotEnoughBytes,
157 })
158 } else {
159 Ok(())
160 }
161 }
162}
163
164
165/// Permissive guard: The resulting slice would have as many instances of a type as will
166/// fit, rounded down. Therefore, this guard will never yield an error.
167pub struct PermissiveGuard;
168
169impl Guard for PermissiveGuard {
170 #[inline]
171 fn check<T>(_: &[u8]) -> Result<(), GuardError> {
172 Ok(())
173 }
174}