zerocopy/
macros.rs

1// Copyright 2023 The Fuchsia Authors
2//
3// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6// This file may not be copied, modified, or distributed except according to
7// those terms.
8
9/// Documents multiple unsafe blocks with a single safety comment.
10///
11/// Invoked as:
12///
13/// ```rust,ignore
14/// safety_comment! {
15///     // Non-doc comments come first.
16///     /// SAFETY:
17///     /// Safety comment starts on its own line.
18///     macro_1!(args);
19///     macro_2! { args };
20///     /// SAFETY:
21///     /// Subsequent safety comments are allowed but not required.
22///     macro_3! { args };
23/// }
24/// ```
25///
26/// The macro invocations are emitted, each decorated with the following
27/// attribute: `#[allow(clippy::undocumented_unsafe_blocks)]`.
28macro_rules! safety_comment {
29    (#[doc = r" SAFETY:"] $($(#[$attr:meta])* $macro:ident!$args:tt;)*) => {
30        #[allow(clippy::undocumented_unsafe_blocks, unused_attributes)]
31        const _: () = { $($(#[$attr])* $macro!$args;)* };
32    }
33}
34
35/// Unsafely implements trait(s) for a type.
36///
37/// # Safety
38///
39/// The trait impl must be sound.
40///
41/// When implementing `TryFromBytes`:
42/// - If no `is_bit_valid` impl is provided, then it must be valid for
43///   `is_bit_valid` to unconditionally return `true`. In other words, it must
44///   be the case that any initialized sequence of bytes constitutes a valid
45///   instance of `$ty`.
46/// - If an `is_bit_valid` impl is provided, then:
47///   - Regardless of whether the provided closure takes a `Ptr<$repr>` or
48///     `&$repr` argument, it must be the case that, given `t: *mut $ty` and
49///     `let r = t as *mut $repr`, `r` refers to an object of equal or lesser
50///     size than the object referred to by `t`.
51///   - If the provided closure takes a `&$repr` argument, then given a `Ptr<'a,
52///     $ty>` which satisfies the preconditions of
53///     `TryFromBytes::<$ty>::is_bit_valid`, it must be guaranteed that the
54///     memory referenced by that `Ptr` always contains a valid `$repr`.
55///   - The alignment of `$repr` is less than or equal to the alignment of
56///     `$ty`.
57///   - The impl of `is_bit_valid` must only return `true` for its argument
58///     `Ptr<$repr>` if the original `Ptr<$ty>` refers to a valid `$ty`.
59macro_rules! unsafe_impl {
60    // Implement `$trait` for `$ty` with no bounds.
61    ($(#[$attr:meta])* $ty:ty: $trait:ident $(; |$candidate:ident: &$repr:ty| $is_bit_valid:expr)?) => {
62        $(#[$attr])*
63        unsafe impl $trait for $ty {
64            unsafe_impl!(@method $trait $(; |$candidate: &$repr| $is_bit_valid)?);
65        }
66    };
67    // Implement all `$traits` for `$ty` with no bounds.
68    ($ty:ty: $($traits:ident),*) => {
69        $( unsafe_impl!($ty: $traits); )*
70    };
71    // This arm is identical to the following one, except it contains a
72    // preceding `const`. If we attempt to handle these with a single arm, there
73    // is an inherent ambiguity between `const` (the keyword) and `const` (the
74    // ident match for `$tyvar:ident`).
75    //
76    // To explain how this works, consider the following invocation:
77    //
78    //   unsafe_impl!(const N: usize, T: ?Sized + Copy => Clone for Foo<T>);
79    //
80    // In this invocation, here are the assignments to meta-variables:
81    //
82    //   |---------------|------------|
83    //   | Meta-variable | Assignment |
84    //   |---------------|------------|
85    //   | $constname    |  N         |
86    //   | $constty      |  usize     |
87    //   | $tyvar        |  T         |
88    //   | $optbound     |  Sized     |
89    //   | $bound        |  Copy      |
90    //   | $trait        |  Clone     |
91    //   | $ty           |  Foo<T>    |
92    //   |---------------|------------|
93    //
94    // The following arm has the same behavior with the exception of the lack of
95    // support for a leading `const` parameter.
96    (
97        $(#[$attr:meta])*
98        const $constname:ident : $constty:ident $(,)?
99        $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
100        => $trait:ident for $ty:ty $(; |$candidate:ident $(: &$ref_repr:ty)? $(: Ptr<$ptr_repr:ty>)?| $is_bit_valid:expr)?
101    ) => {
102        unsafe_impl!(
103            @inner
104            $(#[$attr])*
105            @const $constname: $constty,
106            $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
107            => $trait for $ty $(; |$candidate $(: &$ref_repr)? $(: Ptr<$ptr_repr>)?| $is_bit_valid)?
108        );
109    };
110    (
111        $(#[$attr:meta])*
112        $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
113        => $trait:ident for $ty:ty $(; |$candidate:ident $(: &$ref_repr:ty)? $(: Ptr<$ptr_repr:ty>)?| $is_bit_valid:expr)?
114    ) => {
115        unsafe_impl!(
116            @inner
117            $(#[$attr])*
118            $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
119            => $trait for $ty $(; |$candidate $(: &$ref_repr)? $(: Ptr<$ptr_repr>)?| $is_bit_valid)?
120        );
121    };
122    (
123        @inner
124        $(#[$attr:meta])*
125        $(@const $constname:ident : $constty:ident,)*
126        $($tyvar:ident $(: $(? $optbound:ident +)* + $($bound:ident +)* )?,)*
127        => $trait:ident for $ty:ty $(; |$candidate:ident $(: &$ref_repr:ty)? $(: Ptr<$ptr_repr:ty>)?| $is_bit_valid:expr)?
128    ) => {
129        $(#[$attr])*
130        unsafe impl<$(const $constname: $constty,)* $($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> $trait for $ty {
131            unsafe_impl!(@method $trait $(; |$candidate: $(&$ref_repr)? $(Ptr<$ptr_repr>)?| $is_bit_valid)?);
132        }
133    };
134
135    (@method TryFromBytes ; |$candidate:ident: &$repr:ty| $is_bit_valid:expr) => {
136        #[inline]
137        unsafe fn is_bit_valid(candidate: Ptr<'_, Self>) -> bool {
138            // SAFETY:
139            // - The argument to `cast_unsized` is `|p| p as *mut _` as required
140            //   by that method's safety precondition.
141            // - The caller has promised that the cast results in an object of
142            //   equal or lesser size.
143            // - The caller has promised that `$repr`'s alignment is less than
144            //   or equal to `Self`'s alignment.
145            #[allow(clippy::as_conversions)]
146            let candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) };
147            // SAFETY:
148            // - The caller has promised that the referenced memory region will
149            //   contain a valid `$repr` for `'a`.
150            // - The memory may not be referenced by any mutable references.
151            //   This is a precondition of `is_bit_valid`.
152            // - The memory may not be mutated even via `UnsafeCell`s. This is a
153            //   precondition of `is_bit_valid`.
154            // - There must not exist any references to the same memory region
155            //   which contain `UnsafeCell`s at byte ranges which are not
156            //   identical to the byte ranges at which `T` contains
157            //   `UnsafeCell`s. This is a precondition of `is_bit_valid`.
158            let $candidate: &$repr = unsafe { candidate.as_ref() };
159            $is_bit_valid
160        }
161    };
162    (@method TryFromBytes ; |$candidate:ident: Ptr<$repr:ty>| $is_bit_valid:expr) => {
163        #[inline]
164        unsafe fn is_bit_valid(candidate: Ptr<'_, Self>) -> bool {
165            // SAFETY:
166            // - The argument to `cast_unsized` is `|p| p as *mut _` as required
167            //   by that method's safety precondition.
168            // - The caller has promised that the cast results in an object of
169            //   equal or lesser size.
170            // - The caller has promised that `$repr`'s alignment is less than
171            //   or equal to `Self`'s alignment.
172            #[allow(clippy::as_conversions)]
173            let $candidate = unsafe { candidate.cast_unsized::<$repr, _>(|p| p as *mut _) };
174            $is_bit_valid
175        }
176    };
177    (@method TryFromBytes) => { #[inline(always)] unsafe fn is_bit_valid(_: Ptr<'_, Self>) -> bool { true } };
178    (@method $trait:ident) => {
179        #[allow(clippy::missing_inline_in_public_items)]
180        fn only_derive_is_allowed_to_implement_this_trait() {}
181    };
182    (@method $trait:ident; |$_candidate:ident $(: &$_ref_repr:ty)? $(: NonNull<$_ptr_repr:ty>)?| $_is_bit_valid:expr) => {
183        compile_error!("Can't provide `is_bit_valid` impl for trait other than `TryFromBytes`");
184    };
185}
186
187/// Implements a trait for a type, bounding on each memeber of the power set of
188/// a set of type variables. This is useful for implementing traits for tuples
189/// or `fn` types.
190///
191/// The last argument is the name of a macro which will be called in every
192/// `impl` block, and is expected to expand to the name of the type for which to
193/// implement the trait.
194///
195/// For example, the invocation:
196/// ```ignore
197/// unsafe_impl_for_power_set!(A, B => Foo for type!(...))
198/// ```
199/// ...expands to:
200/// ```ignore
201/// unsafe impl       Foo for type!()     { ... }
202/// unsafe impl<B>    Foo for type!(B)    { ... }
203/// unsafe impl<A, B> Foo for type!(A, B) { ... }
204/// ```
205macro_rules! unsafe_impl_for_power_set {
206    ($first:ident $(, $rest:ident)* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => {
207        unsafe_impl_for_power_set!($($rest),* $(-> $ret)? => $trait for $macro!(...));
208        unsafe_impl_for_power_set!(@impl $first $(, $rest)* $(-> $ret)? => $trait for $macro!(...));
209    };
210    ($(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => {
211        unsafe_impl_for_power_set!(@impl $(-> $ret)? => $trait for $macro!(...));
212    };
213    (@impl $($vars:ident),* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => {
214        unsafe impl<$($vars,)* $($ret)?> $trait for $macro!($($vars),* $(-> $ret)?) {
215            #[allow(clippy::missing_inline_in_public_items)]
216            fn only_derive_is_allowed_to_implement_this_trait() {}
217        }
218    };
219}
220
221/// Expands to an `Option<extern "C" fn>` type with the given argument types and
222/// return type. Designed for use with `unsafe_impl_for_power_set`.
223macro_rules! opt_extern_c_fn {
224    ($($args:ident),* -> $ret:ident) => { Option<extern "C" fn($($args),*) -> $ret> };
225}
226
227/// Expands to a `Option<fn>` type with the given argument types and return
228/// type. Designed for use with `unsafe_impl_for_power_set`.
229macro_rules! opt_fn {
230    ($($args:ident),* -> $ret:ident) => { Option<fn($($args),*) -> $ret> };
231}
232
233/// Implements trait(s) for a type or verifies the given implementation by
234/// referencing an existing (derived) implementation.
235///
236/// This macro exists so that we can provide zerocopy-derive as an optional
237/// dependency and still get the benefit of using its derives to validate that
238/// our trait impls are sound.
239///
240/// When compiling without `--cfg 'feature = "derive"` and without `--cfg test`,
241/// `impl_or_verify!` emits the provided trait impl. When compiling with either
242/// of those cfgs, it is expected that the type in question is deriving the
243/// traits instead. In this case, `impl_or_verify!` emits code which validates
244/// that the given trait impl is at least as restrictive as the the impl emitted
245/// by the custom derive. This has the effect of confirming that the impl which
246/// is emitted when the `derive` feature is disabled is actually sound (on the
247/// assumption that the impl emitted by the custom derive is sound).
248///
249/// The caller is still required to provide a safety comment (e.g. using the
250/// `safety_comment!` macro) . The reason for this restriction is that, while
251/// `impl_or_verify!` can guarantee that the provided impl is sound when it is
252/// compiled with the appropriate cfgs, there is no way to guarantee that it is
253/// ever compiled with those cfgs. In particular, it would be possible to
254/// accidentally place an `impl_or_verify!` call in a context that is only ever
255/// compiled when the `derive` feature is disabled. If that were to happen,
256/// there would be nothing to prevent an unsound trait impl from being emitted.
257/// Requiring a safety comment reduces the likelihood of emitting an unsound
258/// impl in this case, and also provides useful documentation for readers of the
259/// code.
260///
261/// ## Example
262///
263/// ```rust,ignore
264/// // Note that these derives are gated by `feature = "derive"`
265/// #[cfg_attr(any(feature = "derive", test), derive(FromZeroes, FromBytes, AsBytes, Unaligned))]
266/// #[repr(transparent)]
267/// struct Wrapper<T>(T);
268///
269/// safety_comment! {
270///     /// SAFETY:
271///     /// `Wrapper<T>` is `repr(transparent)`, so it is sound to implement any
272///     /// zerocopy trait if `T` implements that trait.
273///     impl_or_verify!(T: FromZeroes => FromZeroes for Wrapper<T>);
274///     impl_or_verify!(T: FromBytes => FromBytes for Wrapper<T>);
275///     impl_or_verify!(T: AsBytes => AsBytes for Wrapper<T>);
276///     impl_or_verify!(T: Unaligned => Unaligned for Wrapper<T>);
277/// }
278/// ```
279macro_rules! impl_or_verify {
280    // The following two match arms follow the same pattern as their
281    // counterparts in `unsafe_impl!`; see the documentation on those arms for
282    // more details.
283    (
284        const $constname:ident : $constty:ident $(,)?
285        $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
286        => $trait:ident for $ty:ty
287    ) => {
288        impl_or_verify!(@impl { unsafe_impl!(
289            const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty
290        ); });
291        impl_or_verify!(@verify $trait, {
292            impl<const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
293        });
294    };
295    (
296        $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
297        => $trait:ident for $ty:ty
298    ) => {
299        impl_or_verify!(@impl { unsafe_impl!(
300            $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty
301        ); });
302        impl_or_verify!(@verify $trait, {
303            impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {}
304        });
305    };
306    (
307        $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),*
308        => $trait:ident for $ty:ty
309    ) => {
310        unsafe_impl!(
311            @inner
312            $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)*
313            => $trait for $ty
314        );
315    };
316    (@impl $impl_block:tt) => {
317        #[cfg(not(any(feature = "derive", test)))]
318        const _: () = { $impl_block };
319    };
320    (@verify $trait:ident, $impl_block:tt) => {
321        #[cfg(any(feature = "derive", test))]
322        const _: () = {
323            trait Subtrait: $trait {}
324            $impl_block
325        };
326    };
327}
328
329/// Implements `KnownLayout` for a sized type.
330macro_rules! impl_known_layout {
331    ($(const $constvar:ident : $constty:ty, $tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
332        $(impl_known_layout!(@inner const $constvar: $constty, $tyvar $(: ?$optbound)? => $ty);)*
333    };
334    ($($tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => {
335        $(impl_known_layout!(@inner , $tyvar $(: ?$optbound)? => $ty);)*
336    };
337    ($($ty:ty),*) => { $(impl_known_layout!(@inner , => $ty);)* };
338    (@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $ty:ty) => {
339        const _: () = {
340            use core::ptr::NonNull;
341
342            // SAFETY: Delegates safety to `DstLayout::for_type`.
343            unsafe impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> KnownLayout for $ty {
344                #[allow(clippy::missing_inline_in_public_items)]
345                fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized {}
346
347                const LAYOUT: DstLayout = DstLayout::for_type::<$ty>();
348
349                // SAFETY: `.cast` preserves address and provenance.
350                //
351                // TODO(#429): Add documentation to `.cast` that promises that
352                // it preserves provenance.
353                #[inline(always)]
354                fn raw_from_ptr_len(bytes: NonNull<u8>, _elems: usize) -> NonNull<Self> {
355                    bytes.cast::<Self>()
356                }
357            }
358        };
359    };
360}
361
362/// Implements `KnownLayout` for a type in terms of the implementation of
363/// another type with the same representation.
364///
365/// # Safety
366///
367/// - `$ty` and `$repr` must have the same:
368///   - Fixed prefix size
369///   - Alignment
370///   - (For DSTs) trailing slice element size
371/// - It must be valid to perform an `as` cast from `*mut $repr` to `*mut $ty`,
372///   and this operation must preserve referent size (ie, `size_of_val_raw`).
373macro_rules! unsafe_impl_known_layout {
374    ($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($repr:ty)] $ty:ty) => {
375        const _: () = {
376            use core::ptr::NonNull;
377
378            unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty {
379                #[allow(clippy::missing_inline_in_public_items)]
380                fn only_derive_is_allowed_to_implement_this_trait() {}
381
382                const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT;
383
384                // SAFETY: All operations preserve address and provenance.
385                // Caller has promised that the `as` cast preserves size.
386                //
387                // TODO(#429): Add documentation to `NonNull::new_unchecked`
388                // that it preserves provenance.
389                #[inline(always)]
390                fn raw_from_ptr_len(bytes: NonNull<u8>, elems: usize) -> NonNull<Self> {
391                    #[allow(clippy::as_conversions)]
392                    let ptr = <$repr>::raw_from_ptr_len(bytes, elems).as_ptr() as *mut Self;
393                    // SAFETY: `ptr` was converted from `bytes`, which is non-null.
394                    unsafe { NonNull::new_unchecked(ptr) }
395                }
396            }
397        };
398    };
399}
400
401/// Uses `align_of` to confirm that a type or set of types have alignment 1.
402///
403/// Note that `align_of<T>` requires `T: Sized`, so this macro doesn't work for
404/// unsized types.
405macro_rules! assert_unaligned {
406    ($ty:ty) => {
407        // We only compile this assertion under `cfg(test)` to avoid taking an
408        // extra non-dev dependency (and making this crate more expensive to
409        // compile for our dependents).
410        #[cfg(test)]
411        static_assertions::const_assert_eq!(core::mem::align_of::<$ty>(), 1);
412    };
413    ($($ty:ty),*) => {
414        $(assert_unaligned!($ty);)*
415    };
416}