1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 //! Defines a trait for structs that can be safely initialized with zero bytes. 4 5 /// Encapsulates the requirement that 6 /// `MaybeUninit::<Self>::zeroed().assume_init()` does not cause undefined 7 /// behavior. This trait in principle could be implemented as just: 8 /// 9 /// ``` 10 /// pub unsafe trait Zeroable: Default { 11 /// const ZERO: Self = unsafe { ::core::mem::MaybeUninit::<Self>::zeroed().assume_init() }; 12 /// } 13 /// ``` 14 /// 15 /// The need for a manual implementation is only because `zeroed()` cannot 16 /// be used as a `const fn` prior to Rust 1.75.0. Once we can assume a new 17 /// enough version of the compiler, we could provide a `#[derive(Zeroable)]` 18 /// macro to check at compile-time that all struct fields are Zeroable, and 19 /// use the above blanket implementation of the `ZERO` constant. 20 /// 21 /// # Safety 22 /// 23 /// Because the implementation of `ZERO` is manual, it does not make 24 /// any assumption on the safety of `zeroed()`. However, other users of the 25 /// trait could use it that way. Do not add this trait to a type unless 26 /// all-zeroes is a valid value for the type. In particular, remember that 27 /// raw pointers can be zero, but references and `NonNull<T>` cannot 28 pub unsafe trait Zeroable: Default { 29 const ZERO: Self; 30 } 31 32 /// A macro that acts similarly to [`core::mem::zeroed()`], only is const 33 /// 34 /// ## Safety 35 /// 36 /// Similar to `core::mem::zeroed()`, except this zeroes padding bits. Zeroed 37 /// padding usually isn't relevant to safety, but might be if a C union is used. 38 /// 39 /// Just like for `core::mem::zeroed()`, an all zero byte pattern might not 40 /// be a valid value for a type, as is the case for references `&T` and `&mut 41 /// T`. Reference types trigger a (denied by default) lint and cause immediate 42 /// undefined behavior if the lint is ignored 43 /// 44 /// ```rust compile_fail 45 /// use const_zero::const_zero; 46 /// // error: any use of this value will cause an error 47 /// // note: `#[deny(const_err)]` on by default 48 /// const STR: &str = unsafe{const_zero!(&'static str)}; 49 /// ``` 50 /// 51 /// `const_zero` does not work on unsized types: 52 /// 53 /// ```rust compile_fail 54 /// use const_zero::const_zero; 55 /// // error[E0277]: the size for values of type `[u8]` cannot be known at compilation time 56 /// const BYTES: [u8] = unsafe{const_zero!([u8])}; 57 /// ``` 58 /// ## Differences with `core::mem::zeroed` 59 /// 60 /// `const_zero` zeroes padding bits, while `core::mem::zeroed` doesn't 61 #[macro_export] 62 macro_rules! const_zero { 63 // This macro to produce a type-generic zero constant is taken from the 64 // const_zero crate (v0.1.1): 65 // 66 // https://docs.rs/const-zero/latest/src/const_zero/lib.rs.html 67 // 68 // and used under MIT license 69 ($type_:ty) => {{ 70 const TYPE_SIZE: ::core::primitive::usize = ::core::mem::size_of::<$type_>(); 71 union TypeAsBytes { 72 bytes: [::core::primitive::u8; TYPE_SIZE], 73 inner: ::core::mem::ManuallyDrop<$type_>, 74 } 75 const ZERO_BYTES: TypeAsBytes = TypeAsBytes { 76 bytes: [0; TYPE_SIZE], 77 }; 78 ::core::mem::ManuallyDrop::<$type_>::into_inner(ZERO_BYTES.inner) 79 }}; 80 } 81 82 /// A wrapper to implement the `Zeroable` trait through the `const_zero` macro. 83 #[macro_export] 84 macro_rules! impl_zeroable { 85 ($type:ty) => { 86 unsafe impl $crate::zeroable::Zeroable for $type { 87 const ZERO: Self = unsafe { $crate::const_zero!($type) }; 88 } 89 }; 90 } 91 92 // bindgen does not derive Default here 93 #[allow(clippy::derivable_impls)] 94 impl Default for crate::bindings::VMStateFlags { 95 fn default() -> Self { 96 Self(0) 97 } 98 } 99 100 impl_zeroable!(crate::bindings::Property__bindgen_ty_1); 101 impl_zeroable!(crate::bindings::Property); 102 impl_zeroable!(crate::bindings::VMStateFlags); 103 impl_zeroable!(crate::bindings::VMStateField); 104 impl_zeroable!(crate::bindings::VMStateDescription); 105 impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_1); 106 impl_zeroable!(crate::bindings::MemoryRegionOps__bindgen_ty_2); 107 impl_zeroable!(crate::bindings::MemoryRegionOps); 108 impl_zeroable!(crate::bindings::MemTxAttrs); 109