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 #[allow(unused_qualifications)] // for `core::ptr::NonNull`
391 fn raw_from_ptr_len(bytes: NonNull<u8>, elems: usize) -> NonNull<Self> {
392 #[allow(clippy::as_conversions)]
393 let ptr = <$repr>::raw_from_ptr_len(bytes, elems).as_ptr() as *mut Self;
394 // SAFETY: `ptr` was converted from `bytes`, which is non-null.
395 unsafe { NonNull::new_unchecked(ptr) }
396 }
397 }
398 };
399 };
400}
401
402/// Uses `align_of` to confirm that a type or set of types have alignment 1.
403///
404/// Note that `align_of<T>` requires `T: Sized`, so this macro doesn't work for
405/// unsized types.
406macro_rules! assert_unaligned {
407 ($ty:ty) => {
408 // We only compile this assertion under `cfg(test)` to avoid taking an
409 // extra non-dev dependency (and making this crate more expensive to
410 // compile for our dependents).
411 #[cfg(test)]
412 static_assertions::const_assert_eq!(core::mem::align_of::<$ty>(), 1);
413 };
414 ($($ty:ty),*) => {
415 $(assert_unaligned!($ty);)*
416 };
417}
418