win_crypto_ng/helpers/bytes.rs
1//! Byte fiddling utilities
2//!
3//! Define [FromBytes](trait.FromBytes.html) and [AsBytes](trait.AsBytes.html)
4//! traits, which allow for safe data conversion assuming the data meets certain
5//! layout-specific restrictions.
6//! See documentation for [AsBytes](trait.AsBytes.html) for more details.
7//!
8//! These traits are implemented automatically for sized data structures if they
9//! implement [Pod](trait.Pod.html) trait.
10
11use core::alloc::Layout;
12use core::{mem, ptr, slice};
13
14/// Checks if a pointer can be a valid Rust reference.
15pub(crate) fn ptr_ref_cast<T, U>(ptr: *const U) -> *const T {
16 assert_ne!(ptr, ptr::null());
17 assert_eq!(ptr as usize % mem::align_of::<T>(), 0);
18 ptr as *const _
19}
20
21/// Attempts to cast the pointer to byte slice to a pointer of a generic slice.
22/// Adjusts the length metadata as required.
23/// Panics if the pointer is null.
24///
25/// # Safety
26///
27pub unsafe fn ptr_slice_cast<T>(ptr: *const [u8]) -> *const [T] {
28 assert_ne!(ptr as *const (), ptr::null());
29 // SAFETY: [u8] is 1-byte aligned so no need to check that before deref
30 let len = (*ptr).len();
31
32 let new_len = len * mem::size_of::<u8>() / mem::size_of::<T>();
33
34 let slice = slice::from_raw_parts(ptr as *const T, new_len);
35 slice as *const _ as *const [T]
36}
37
38/// Marker trait for types that can be safely converted to bytes.
39///
40/// # Safety
41/// Implementee MUST be `#[repr(C)]` and:
42/// - not contain any pointer types that are dereferenced,
43/// - itself or any of its members MUST NOT implement a custom destructor,
44/// - be inhabited,
45/// - allow any bit pattern
46///
47/// ## Layout
48/// Implementee also needs to be layout-compatible with [u8].
49pub unsafe trait AsBytes {
50 fn as_bytes(&self) -> &[u8] {
51 let len = mem::size_of_val(self);
52 // SAFETY: Guaranteed by documented unsafe impl invariants.
53 unsafe { slice::from_raw_parts(self as *const _ as *const u8, len) }
54 }
55
56 fn into_bytes(self: Box<Self>) -> Box<[u8]> {
57 let len = mem::size_of_val(self.as_ref());
58 // SAFETY: Guaranteed by documented unsafe impl invariants of `AsBytes`.
59 let ptr = Box::into_raw(self);
60 unsafe {
61 let slice = slice::from_raw_parts_mut(ptr as *mut _ as *mut u8, len);
62
63 Box::from_raw(slice)
64 }
65 }
66}
67
68/// Marker trait for types that can be safely converted to bytes.
69pub unsafe trait FromBytes {
70 /// Specified the minimum layout requirements for the allocation:
71 /// - is at least as big as `MIN_LAYOUT.size()`
72 /// - referenced/pointed data is at least as aligned as `MIN_LAYOUT.align()`
73 ///
74 /// For DSTs, final size should be exactly the same as the allocation's.
75 ///
76 /// # Safety
77 /// In Rust, it is considered [UB] for pointers/references/`Box<T>`es to
78 /// be dangling, unaligned or pointing to invalid value.
79 ///
80 /// The alignment check is done using `MIN_LAYOUT` and thus can cause UB if
81 /// implemented incorrectly.
82 ///
83 /// [UB]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
84 const MIN_LAYOUT: Layout;
85
86 fn from_bytes(bytes: &[u8]) -> &Self {
87 let min_layout = Self::MIN_LAYOUT;
88 // Make sure the allocation meets the expected layout requirements
89 assert!(bytes.len() >= min_layout.size());
90 assert_eq!(bytes.as_ptr() as usize % min_layout.align(), 0);
91
92 let old_size = mem::size_of_val(bytes);
93 // SAFETY: It's up to the implementer to provide a sound
94 // `Self::ptr_cast` implementation.
95 let new = unsafe { &*Self::ptr_cast(bytes) };
96
97 let new_size = mem::size_of_val(new);
98 // Make sure we don't leak data/forget any information when adjusting
99 // the (possibly wide) pointer
100 assert_eq!(old_size, new_size);
101
102 new
103 }
104
105 fn from_boxed(boxed: Box<[u8]>) -> Box<Self> {
106 let min_layout = Self::MIN_LAYOUT;
107 // Make sure the allocation meets the expected layout requirements
108 assert!(boxed.len() >= min_layout.size());
109 assert_eq!(boxed.as_ptr() as usize % min_layout.align(), 0);
110
111 let old_size = mem::size_of_val(boxed.as_ref());
112
113 let ptr = Box::into_raw(boxed);
114 // SAFETY: It's up to the implementer to provide a sound
115 // `Self::ptr_cast` implementation.
116 let new = unsafe { Box::from_raw(Self::ptr_cast(ptr) as *mut Self) };
117
118 let new_size = mem::size_of_val(new.as_ref());
119 // Make sure we don't leak data/forget any information when adjusting
120 // the (possibly wide) pointer
121 assert_eq!(old_size, new_size);
122
123 new
124 }
125
126 #[doc(hidden)]
127 unsafe fn ptr_cast(source: *const [u8]) -> *const Self;
128}
129
130unsafe impl FromBytes for [u16] {
131 // Allow for empty slices but require correct alignment
132 const MIN_LAYOUT: Layout =
133 unsafe { Layout::from_size_align_unchecked(0, mem::align_of::<u16>()) };
134 unsafe fn ptr_cast(source: *const [u8]) -> *const Self {
135 ptr_slice_cast(source)
136 }
137}
138
139unsafe impl FromBytes for [u8] {
140 // Allow for empty slices but require correct alignment
141 const MIN_LAYOUT: Layout =
142 unsafe { Layout::from_size_align_unchecked(0, mem::align_of::<u8>()) };
143 unsafe fn ptr_cast(source: *const [u8]) -> *const [u8] {
144 source
145 }
146
147 fn from_bytes(bytes: &[u8]) -> &Self {
148 bytes
149 }
150 fn from_boxed(boxed: Box<[u8]>) -> Box<Self> {
151 boxed
152 }
153}
154
155/// Marker trait that can be safely converted from and into bytes.
156///
157/// Automatically implements [AsBytes] and [FromBytes].
158/// # Safety
159/// See documentation for [AsBytes] for safety invariants that need to be upheld.
160pub unsafe trait Pod: Sized {}
161
162unsafe impl<T> AsBytes for T where T: Pod {}
163unsafe impl<T> FromBytes for T
164where
165 T: Pod,
166{
167 const MIN_LAYOUT: Layout = Layout::new::<Self>();
168
169 unsafe fn ptr_cast(ptr: *const [u8]) -> *const Self {
170 ptr_ref_cast(ptr as *const ())
171 }
172}
173
174unsafe impl Pod for u32 {} // Ignores endianness