• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::mem::size_of;
6 use std::slice::{from_raw_parts, from_raw_parts_mut};
7 
8 /// Types for which it is safe to initialize from raw data.
9 ///
10 /// A type `T` is `DataInit` if and only if it can be initialized by reading its contents from a
11 /// byte array.  This is generally true for all plain-old-data structs.  It is notably not true for
12 /// any type that includes a reference.
13 ///
14 /// Implementing this trait guarantees that it is safe to instantiate the struct with random data.
15 pub unsafe trait DataInit: Copy + Send + Sync {
16     /// Converts a slice of raw data into a reference of `Self`.
17     ///
18     /// The value of `data` is not copied. Instead a reference is made from the given slice. The
19     /// value of `Self` will depend on the representation of the type in memory, and may change in
20     /// an unstable fashion.
21     ///
22     /// This will return `None` if the length of data does not match the size of `Self`, or if the
23     /// data is not aligned for the type of `Self`.
from_slice(data: &[u8]) -> Option<&Self>24     fn from_slice(data: &[u8]) -> Option<&Self> {
25         // Early out to avoid an unneeded `align_to` call.
26         if data.len() != size_of::<Self>() {
27             return None;
28         }
29 
30         // Safe because the DataInit trait asserts any data is valid for this type, and we ensured
31         // the size of the pointer's buffer is the correct size. The `align_to` method ensures that
32         // we don't have any unaligned references. This aliases a pointer, but because the pointer
33         // is from a const slice reference, there are no mutable aliases. Finally, the reference
34         // returned can not outlive data because they have equal implicit lifetime constraints.
35         match unsafe { data.align_to::<Self>() } {
36             ([], [mid], []) => Some(mid),
37             _ => None,
38         }
39     }
40 
41     /// Converts a mutable slice of raw data into a mutable reference of `Self`.
42     ///
43     /// Because `Self` is made from a reference to the mutable slice`, mutations to the returned
44     /// reference are immediately reflected in `data`. The value of the returned `Self` will depend
45     /// on the representation of the type in memory, and may change in an unstable fashion.
46     ///
47     /// This will return `None` if the length of data does not match the size of `Self`, or if the
48     /// data is not aligned for the type of `Self`.
from_mut_slice(data: &mut [u8]) -> Option<&mut Self>49     fn from_mut_slice(data: &mut [u8]) -> Option<&mut Self> {
50         // Early out to avoid an unneeded `align_to_mut` call.
51         if data.len() != size_of::<Self>() {
52             return None;
53         }
54 
55         // Safe because the DataInit trait asserts any data is valid for this type, and we ensured
56         // the size of the pointer's buffer is the correct size. The `align_to` method ensures that
57         // we don't have any unaligned references. This aliases a pointer, but because the pointer
58         // is from a mut slice reference, we borrow the passed in mutable reference. Finally, the
59         // reference returned can not outlive data because they have equal implicit lifetime
60         // constraints.
61         match unsafe { data.align_to_mut::<Self>() } {
62             ([], [mid], []) => Some(mid),
63             _ => None,
64         }
65     }
66 
67     /// Converts a reference to `self` into a slice of bytes.
68     ///
69     /// The value of `self` is not copied. Instead, the slice is made from a reference to `self`.
70     /// The value of bytes in the returned slice will depend on the representation of the type in
71     /// memory, and may change in an unstable fashion.
as_slice(&self) -> &[u8]72     fn as_slice(&self) -> &[u8] {
73         // Safe because the entire size of self is accessible as bytes because the trait guarantees
74         // it. The lifetime of the returned slice is the same as the passed reference, so that no
75         // dangling pointers will result from this pointer alias.
76         unsafe { from_raw_parts(self as *const Self as *const u8, size_of::<Self>()) }
77     }
78 
79     /// Converts a mutable reference to `self` into a mutable slice of bytes.
80     ///
81     /// Because the slice is made from a reference to `self`, mutations to the returned slice are
82     /// immediately reflected in `self`. The value of bytes in the returned slice will depend on
83     /// the representation of the type in memory, and may change in an unstable fashion.
as_mut_slice(&mut self) -> &mut [u8]84     fn as_mut_slice(&mut self) -> &mut [u8] {
85         // Safe because the entire size of self is accessible as bytes because the trait guarantees
86         // it. The trait also guarantees that any combination of bytes is valid for this type, so
87         // modifying them in the form of a byte slice is valid. The lifetime of the returned slice
88         // is the same as the passed reference, so that no dangling pointers will result from this
89         // pointer alias. Although this does alias a mutable pointer, we do so by exclusively
90         // borrowing the given mutable reference.
91         unsafe { from_raw_parts_mut(self as *mut Self as *mut u8, size_of::<Self>()) }
92     }
93 }
94 
95 // All intrinsic types and arays of intrinsic types are DataInit.  They are just numbers.
96 macro_rules! array_data_init {
97     ($T:ty, $($N:expr)+) => {
98         $(
99             unsafe impl DataInit for [$T; $N] {}
100         )+
101     }
102 }
103 macro_rules! data_init_type {
104     ($($T:ident),*) => {
105         $(
106             unsafe impl DataInit for $T {}
107             array_data_init! {
108                 $T,
109                 0  1  2  3  4  5  6  7  8  9
110                 10 11 12 13 14 15 16 17 18 19
111                 20 21 22 23 24 25 26 27 28 29
112                 30 31 32
113             }
114         )*
115         #[cfg(test)]
116         mod data_init_tests {
117             use std::mem::{size_of, align_of};
118             use crate::DataInit;
119 
120             #[test]
121             fn from_slice_alignment() {
122                 let mut v = [0u8; 32];
123                 $(
124                     let (pre, _, _) = unsafe { v.align_to::<$T>() };
125                     let pre_len = pre.len();
126 
127                     let aligned_v = &mut v[pre_len..pre_len + size_of::<$T>()];
128 
129                     let from_aligned = $T::from_slice(aligned_v);
130                     assert_eq!(from_aligned, Some(&0));
131 
132                     let from_aligned_mut = $T::from_mut_slice(aligned_v);
133                     assert_eq!(from_aligned_mut, Some(&mut 0));
134 
135                     for i in 1..size_of::<$T>() {
136                         let begin = pre_len + i;
137                         let end = begin + size_of::<$T>();
138                         let unaligned_v = &mut v[begin..end];
139 
140                         let from_unaligned = $T::from_slice(unaligned_v);
141                         if align_of::<$T>() != 1 {
142                             assert_eq!(from_unaligned, None);
143                         }
144 
145                         let from_unaligned_mut = $T::from_mut_slice(unaligned_v);
146                         if align_of::<$T>() != 1 {
147                             assert_eq!(from_unaligned_mut, None);
148                         }
149                     }
150                 )*
151 
152             }
153         }
154     };
155 }
156 data_init_type!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
157 
158 pub mod endian;
159 pub use crate::endian::*;
160 
161 pub mod volatile_memory;
162 pub use crate::volatile_memory::*;
163