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