/rust/registry/src/index.crates.io-6f17d22bba15001f/object-0.36.1/src/pod.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! Tools for converting file format structures to and from bytes. |
2 | | //! |
3 | | //! This module should be replaced once rust provides safe transmutes. |
4 | | |
5 | | // This module provides functions for both read and write features. |
6 | | #![cfg_attr( |
7 | | not(all(feature = "read_core", feature = "write_core")), |
8 | | allow(dead_code) |
9 | | )] |
10 | | |
11 | | use core::{mem, result, slice}; |
12 | | |
13 | | type Result<T> = result::Result<T, ()>; |
14 | | |
15 | | /// A trait for types that can safely be converted from and to byte slices. |
16 | | /// |
17 | | /// # Safety |
18 | | /// A type that is `Pod` must: |
19 | | /// - be `#[repr(C)]` or `#[repr(transparent)]` |
20 | | /// - have no invalid byte values |
21 | | /// - have no padding |
22 | | pub unsafe trait Pod: Copy + 'static {} |
23 | | |
24 | | /// Cast the head of a byte slice to a `Pod` type. |
25 | | /// |
26 | | /// Returns the type and the tail of the byte slice. |
27 | | /// |
28 | | /// Returns an error if the byte slice is too short or the alignment is invalid. |
29 | | #[inline] |
30 | 0 | pub fn from_bytes<T: Pod>(data: &[u8]) -> Result<(&T, &[u8])> { |
31 | 0 | let size = mem::size_of::<T>(); |
32 | 0 | let tail = data.get(size..).ok_or(())?; |
33 | 0 | let ptr = data.as_ptr(); |
34 | 0 | if (ptr as usize) % mem::align_of::<T>() != 0 { |
35 | 0 | return Err(()); |
36 | 0 | } |
37 | 0 | // Safety: |
38 | 0 | // The alignment and size are checked by this function. |
39 | 0 | // The Pod trait ensures the type is valid to cast from bytes. |
40 | 0 | let val = unsafe { &*ptr.cast() }; |
41 | 0 | Ok((val, tail)) |
42 | 0 | } Unexecuted instantiation: object::pod::from_bytes::<object::elf::FileHeader64<object::endian::LittleEndian>> Unexecuted instantiation: object::pod::from_bytes::<object::elf::NoteHeader32<object::endian::LittleEndian>> Unexecuted instantiation: object::pod::from_bytes::<object::elf::SectionHeader64<object::endian::LittleEndian>> Unexecuted instantiation: object::pod::from_bytes::<object::elf::CompressionHeader64<object::endian::LittleEndian>> Unexecuted instantiation: object::pod::from_bytes::<object::endian::U32Bytes<object::endian::BigEndian>> Unexecuted instantiation: object::pod::from_bytes::<object::endian::U16Bytes<object::endian::LittleEndian>> Unexecuted instantiation: object::pod::from_bytes::<object::pe::ImageBaseRelocation> Unexecuted instantiation: object::pod::from_bytes::<object::pe::ImageExportDirectory> Unexecuted instantiation: object::pod::from_bytes::<object::pe::ImageImportDescriptor> Unexecuted instantiation: object::pod::from_bytes::<object::pe::ImageResourceDataEntry> Unexecuted instantiation: object::pod::from_bytes::<object::pe::ImageResourceDirectory> Unexecuted instantiation: object::pod::from_bytes::<object::pe::ImageDelayloadDescriptor> Unexecuted instantiation: object::pod::from_bytes::<u8> |
43 | | |
44 | | /// Cast the head of a mutable byte slice to a `Pod` type. |
45 | | /// |
46 | | /// Returns the type and the tail of the byte slice. |
47 | | /// |
48 | | /// Returns an error if the byte slice is too short or the alignment is invalid. |
49 | | #[inline] |
50 | 0 | pub fn from_bytes_mut<T: Pod>(data: &mut [u8]) -> Result<(&mut T, &mut [u8])> { |
51 | 0 | let size = mem::size_of::<T>(); |
52 | 0 | if size > data.len() { |
53 | 0 | return Err(()); |
54 | 0 | } |
55 | 0 | let (data, tail) = data.split_at_mut(size); |
56 | 0 | let ptr = data.as_mut_ptr(); |
57 | 0 | if (ptr as usize) % mem::align_of::<T>() != 0 { |
58 | 0 | return Err(()); |
59 | 0 | } |
60 | 0 | // Safety: |
61 | 0 | // The alignment and size are checked by this function. |
62 | 0 | // The Pod trait ensures the type is valid to cast from bytes. |
63 | 0 | let val = unsafe { &mut *ptr.cast() }; |
64 | 0 | Ok((val, tail)) |
65 | 0 | } |
66 | | |
67 | | /// Cast the head of a byte slice to a slice of a `Pod` type. |
68 | | /// |
69 | | /// Returns the type slice and the tail of the byte slice. |
70 | | /// |
71 | | /// Returns an error if the byte slice is too short or the alignment is invalid. |
72 | | #[inline] |
73 | 0 | pub fn slice_from_bytes<T: Pod>(data: &[u8], count: usize) -> Result<(&[T], &[u8])> { |
74 | 0 | let size = count.checked_mul(mem::size_of::<T>()).ok_or(())?; |
75 | 0 | let tail = data.get(size..).ok_or(())?; |
76 | 0 | let ptr = data.as_ptr(); |
77 | 0 | if (ptr as usize) % mem::align_of::<T>() != 0 { |
78 | 0 | return Err(()); |
79 | 0 | } |
80 | 0 | // Safety: |
81 | 0 | // The alignment and size are checked by this function. |
82 | 0 | // The Pod trait ensures the type is valid to cast from bytes. |
83 | 0 | let slice = unsafe { slice::from_raw_parts(ptr.cast(), count) }; |
84 | 0 | Ok((slice, tail)) |
85 | 0 | } Unexecuted instantiation: object::pod::slice_from_bytes::<object::elf::SectionHeader64<object::endian::LittleEndian>> Unexecuted instantiation: object::pod::slice_from_bytes::<object::elf::Sym64<object::endian::LittleEndian>> Unexecuted instantiation: object::pod::slice_from_bytes::<object::endian::U32Bytes<object::endian::LittleEndian>> Unexecuted instantiation: object::pod::slice_from_bytes::<object::endian::U16Bytes<object::endian::LittleEndian>> Unexecuted instantiation: object::pod::slice_from_bytes::<object::endian::U32Bytes<object::endian::LittleEndian>> Unexecuted instantiation: object::pod::slice_from_bytes::<object::pe::ImageDataDirectory> Unexecuted instantiation: object::pod::slice_from_bytes::<object::pe::ImageResourceDirectoryEntry> |
86 | | |
87 | | /// Cast the head of a mutable byte slice to a slice of a `Pod` type. |
88 | | /// |
89 | | /// Returns the type slice and the tail of the byte slice. |
90 | | /// |
91 | | /// Returns an error if the byte slice is too short or the alignment is invalid. |
92 | | #[inline] |
93 | 0 | pub fn slice_from_bytes_mut<T: Pod>( |
94 | 0 | data: &mut [u8], |
95 | 0 | count: usize, |
96 | 0 | ) -> Result<(&mut [T], &mut [u8])> { |
97 | 0 | let size = count.checked_mul(mem::size_of::<T>()).ok_or(())?; |
98 | 0 | if size > data.len() { |
99 | 0 | return Err(()); |
100 | 0 | } |
101 | 0 | let (data, tail) = data.split_at_mut(size); |
102 | 0 | let ptr = data.as_mut_ptr(); |
103 | 0 | if (ptr as usize) % mem::align_of::<T>() != 0 { |
104 | 0 | return Err(()); |
105 | 0 | } |
106 | 0 | // Safety: |
107 | 0 | // The alignment and size are checked by this function. |
108 | 0 | // The Pod trait ensures the type is valid to cast from bytes. |
109 | 0 | let slice = unsafe { slice::from_raw_parts_mut(ptr.cast(), count) }; |
110 | 0 | Ok((slice, tail)) |
111 | 0 | } |
112 | | |
113 | | /// Cast all of a byte slice to a slice of a `Pod` type. |
114 | | /// |
115 | | /// Returns the type slice. |
116 | | /// |
117 | | /// Returns an error if the size of the byte slice is not an exact multiple |
118 | | /// of the type size, or the alignment is invalid. |
119 | | #[inline] |
120 | 0 | pub fn slice_from_all_bytes<T: Pod>(data: &[u8]) -> Result<&[T]> { |
121 | 0 | let count = data.len() / mem::size_of::<T>(); |
122 | 0 | let (slice, tail) = slice_from_bytes(data, count)?; |
123 | 0 | if !tail.is_empty() { |
124 | 0 | return Err(()); |
125 | 0 | } |
126 | 0 | Ok(slice) |
127 | 0 | } Unexecuted instantiation: object::pod::slice_from_all_bytes::<object::elf::Sym64<object::endian::LittleEndian>> Unexecuted instantiation: object::pod::slice_from_all_bytes::<object::endian::U32Bytes<object::endian::LittleEndian>> Unexecuted instantiation: object::pod::slice_from_all_bytes::<_> |
128 | | |
129 | | /// Cast all of a byte slice to a slice of a `Pod` type. |
130 | | /// |
131 | | /// Returns the type slice. |
132 | | /// |
133 | | /// Returns an error if the size of the byte slice is not an exact multiple |
134 | | /// of the type size, or the alignment is invalid. |
135 | | #[inline] |
136 | 0 | pub fn slice_from_all_bytes_mut<T: Pod>(data: &mut [u8]) -> Result<&mut [T]> { |
137 | 0 | let count = data.len() / mem::size_of::<T>(); |
138 | 0 | let (slice, tail) = slice_from_bytes_mut(data, count)?; |
139 | 0 | if !tail.is_empty() { |
140 | 0 | return Err(()); |
141 | 0 | } |
142 | 0 | Ok(slice) |
143 | 0 | } |
144 | | |
145 | | /// Cast a `Pod` type to a byte slice. |
146 | | #[inline] |
147 | 0 | pub fn bytes_of<T: Pod>(val: &T) -> &[u8] { |
148 | 0 | let size = mem::size_of::<T>(); |
149 | 0 | // Safety: |
150 | 0 | // Any alignment is allowed. |
151 | 0 | // The size is determined in this function. |
152 | 0 | // The Pod trait ensures the type is valid to cast to bytes. |
153 | 0 | unsafe { slice::from_raw_parts(slice::from_ref(val).as_ptr().cast(), size) } |
154 | 0 | } |
155 | | |
156 | | /// Cast a `Pod` type to a mutable byte slice. |
157 | | #[inline] |
158 | 0 | pub fn bytes_of_mut<T: Pod>(val: &mut T) -> &mut [u8] { |
159 | 0 | let size = mem::size_of::<T>(); |
160 | 0 | // Safety: |
161 | 0 | // Any alignment is allowed. |
162 | 0 | // The size is determined in this function. |
163 | 0 | // The Pod trait ensures the type is valid to cast to bytes. |
164 | 0 | unsafe { slice::from_raw_parts_mut(slice::from_mut(val).as_mut_ptr().cast(), size) } |
165 | 0 | } |
166 | | |
167 | | /// Cast a slice of a `Pod` type to a byte slice. |
168 | | #[inline] |
169 | 0 | pub fn bytes_of_slice<T: Pod>(val: &[T]) -> &[u8] { |
170 | 0 | let size = val.len().wrapping_mul(mem::size_of::<T>()); |
171 | 0 | // Safety: |
172 | 0 | // Any alignment is allowed. |
173 | 0 | // The size is determined in this function. |
174 | 0 | // The Pod trait ensures the type is valid to cast to bytes. |
175 | 0 | unsafe { slice::from_raw_parts(val.as_ptr().cast(), size) } |
176 | 0 | } |
177 | | |
178 | | /// Cast a slice of a `Pod` type to a mutable byte slice. |
179 | | #[inline] |
180 | 0 | pub fn bytes_of_slice_mut<T: Pod>(val: &mut [T]) -> &mut [u8] { |
181 | 0 | let size = val.len().wrapping_mul(mem::size_of::<T>()); |
182 | 0 | // Safety: |
183 | 0 | // Any alignment is allowed. |
184 | 0 | // The size is determined in this function. |
185 | 0 | // The Pod trait ensures the type is valid to cast to bytes. |
186 | 0 | unsafe { slice::from_raw_parts_mut(val.as_mut_ptr().cast(), size) } |
187 | 0 | } |
188 | | |
189 | | macro_rules! unsafe_impl_pod { |
190 | | ($($struct_name:ident),+ $(,)?) => { |
191 | | $( |
192 | | unsafe impl Pod for $struct_name { } |
193 | | )+ |
194 | | } |
195 | | } |
196 | | |
197 | | unsafe_impl_pod!(u8, u16, u32, u64); |
198 | | |
199 | | unsafe impl<const N: usize, T: Pod> Pod for [T; N] {} |
200 | | |
201 | | #[cfg(test)] |
202 | | mod tests { |
203 | | use super::*; |
204 | | |
205 | | #[test] |
206 | | fn single() { |
207 | | let x = u32::to_be(0x0123_4567); |
208 | | let mut x_mut = x; |
209 | | let bytes = bytes_of(&x); |
210 | | let bytes_mut = bytes_of_mut(&mut x_mut); |
211 | | assert_eq!(bytes, [0x01, 0x23, 0x45, 0x67]); |
212 | | assert_eq!(bytes, bytes_mut); |
213 | | |
214 | | let x16 = [u16::to_be(0x0123), u16::to_be(0x4567)]; |
215 | | |
216 | | let (y, tail) = from_bytes::<u32>(bytes).unwrap(); |
217 | | let (y_mut, tail_mut) = from_bytes_mut::<u32>(bytes_mut).unwrap(); |
218 | | assert_eq!(*y, x); |
219 | | assert_eq!(y, y_mut); |
220 | | assert_eq!(tail, &[]); |
221 | | assert_eq!(tail, tail_mut); |
222 | | |
223 | | let (y, tail) = from_bytes::<u16>(bytes).unwrap(); |
224 | | let (y_mut, tail_mut) = from_bytes_mut::<u16>(bytes_mut).unwrap(); |
225 | | assert_eq!(*y, x16[0]); |
226 | | assert_eq!(y, y_mut); |
227 | | assert_eq!(tail, &bytes[2..]); |
228 | | assert_eq!(tail, tail_mut); |
229 | | |
230 | | let (y, tail) = from_bytes::<u16>(&bytes[2..]).unwrap(); |
231 | | let (y_mut, tail_mut) = from_bytes_mut::<u16>(&mut bytes_mut[2..]).unwrap(); |
232 | | assert_eq!(*y, x16[1]); |
233 | | assert_eq!(y, y_mut); |
234 | | assert_eq!(tail, &[]); |
235 | | assert_eq!(tail, tail_mut); |
236 | | |
237 | | assert_eq!(from_bytes::<u16>(&bytes[1..]), Err(())); |
238 | | assert_eq!(from_bytes::<u16>(&bytes[3..]), Err(())); |
239 | | assert_eq!(from_bytes::<u16>(&bytes[4..]), Err(())); |
240 | | assert_eq!(from_bytes_mut::<u16>(&mut bytes_mut[1..]), Err(())); |
241 | | assert_eq!(from_bytes_mut::<u16>(&mut bytes_mut[3..]), Err(())); |
242 | | assert_eq!(from_bytes_mut::<u16>(&mut bytes_mut[4..]), Err(())); |
243 | | } |
244 | | |
245 | | #[test] |
246 | | fn slice() { |
247 | | let x = [ |
248 | | u16::to_be(0x0123), |
249 | | u16::to_be(0x4567), |
250 | | u16::to_be(0x89ab), |
251 | | u16::to_be(0xcdef), |
252 | | ]; |
253 | | let mut x_mut = x; |
254 | | |
255 | | let bytes = bytes_of_slice(&x); |
256 | | let bytes_mut = bytes_of_slice_mut(&mut x_mut); |
257 | | assert_eq!(bytes, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); |
258 | | assert_eq!(bytes, bytes_mut); |
259 | | |
260 | | let (y, tail) = slice_from_bytes::<u16>(bytes, 4).unwrap(); |
261 | | let (y_mut, tail_mut) = slice_from_bytes_mut::<u16>(bytes_mut, 4).unwrap(); |
262 | | assert_eq!(y, x); |
263 | | assert_eq!(y, y_mut); |
264 | | assert_eq!(tail, &[]); |
265 | | assert_eq!(tail, tail_mut); |
266 | | |
267 | | let (y, tail) = slice_from_bytes::<u16>(&bytes[2..], 2).unwrap(); |
268 | | let (y_mut, tail_mut) = slice_from_bytes_mut::<u16>(&mut bytes_mut[2..], 2).unwrap(); |
269 | | assert_eq!(y, &x[1..3]); |
270 | | assert_eq!(y, y_mut); |
271 | | assert_eq!(tail, &bytes[6..]); |
272 | | assert_eq!(tail, tail_mut); |
273 | | |
274 | | assert_eq!(slice_from_bytes::<u16>(bytes, 5), Err(())); |
275 | | assert_eq!(slice_from_bytes::<u16>(&bytes[2..], 4), Err(())); |
276 | | assert_eq!(slice_from_bytes::<u16>(&bytes[1..], 2), Err(())); |
277 | | assert_eq!(slice_from_bytes_mut::<u16>(bytes_mut, 5), Err(())); |
278 | | assert_eq!(slice_from_bytes_mut::<u16>(&mut bytes_mut[2..], 4), Err(())); |
279 | | assert_eq!(slice_from_bytes_mut::<u16>(&mut bytes_mut[1..], 2), Err(())); |
280 | | } |
281 | | } |