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)]`. 28 macro_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, if `$ty` and `$repr` are different types, then it 49 /// must be the case that, given `t: *mut $ty` and `let r = t as *mut 50 /// $repr`: 51 /// - `r` refers to an object of equal or lesser size than the object 52 /// referred to by `t`. 53 /// - `r` refers to an object with `UnsafeCell`s at the same byte ranges as 54 /// the object referred to by `t`. 55 /// - If the provided closure takes a `&$repr` argument, then given a `Ptr<'a, 56 /// $ty>` which satisfies the preconditions of 57 /// `TryFromBytes::<$ty>::is_bit_valid`, it must be guaranteed that the 58 /// memory referenced by that `Ptr` always contains a valid `$repr`. 59 /// - The impl of `is_bit_valid` must only return `true` for its argument 60 /// `Ptr<$repr>` if the original `Ptr<$ty>` refers to a valid `$ty`. 61 macro_rules! unsafe_impl { 62 // Implement `$trait` for `$ty` with no bounds. 63 ($(#[$attr:meta])* $ty:ty: $trait:ident $(; |$candidate:ident: MaybeAligned<$repr:ty>| $is_bit_valid:expr)?) => { 64 $(#[$attr])* 65 unsafe impl $trait for $ty { 66 unsafe_impl!(@method $trait $(; |$candidate: MaybeAligned<$repr>| $is_bit_valid)?); 67 } 68 }; 69 70 // Implement all `$traits` for `$ty` with no bounds. 71 // 72 // The 2 arms under this one are there so we can apply 73 // N attributes for each one of M trait implementations. 74 // The simple solution of: 75 // 76 // ($(#[$attrs:meta])* $ty:ty: $($traits:ident),*) => { 77 // $( unsafe_impl!( $(#[$attrs])* $ty: $traits ) );* 78 // } 79 // 80 // Won't work. The macro processor sees that the outer repetition 81 // contains both $attrs and $traits and expects them to match the same 82 // amount of fragments. 83 // 84 // To solve this we must: 85 // 1. Pack the attributes into a single token tree fragment we can match over. 86 // 2. Expand the traits. 87 // 3. Unpack and expand the attributes. 88 ($(#[$attrs:meta])* $ty:ty: $($traits:ident),*) => { 89 unsafe_impl!(@impl_traits_with_packed_attrs { $(#[$attrs])* } $ty: $($traits),*) 90 }; 91 92 (@impl_traits_with_packed_attrs $attrs:tt $ty:ty: $($traits:ident),*) => { 93 $( unsafe_impl!(@unpack_attrs $attrs $ty: $traits); )* 94 }; 95 96 (@unpack_attrs { $(#[$attrs:meta])* } $ty:ty: $traits:ident) => { 97 unsafe_impl!($(#[$attrs])* $ty: $traits); 98 }; 99 100 // This arm is identical to the following one, except it contains a 101 // preceding `const`. If we attempt to handle these with a single arm, there 102 // is an inherent ambiguity between `const` (the keyword) and `const` (the 103 // ident match for `$tyvar:ident`). 104 // 105 // To explain how this works, consider the following invocation: 106 // 107 // unsafe_impl!(const N: usize, T: ?Sized + Copy => Clone for Foo<T>); 108 // 109 // In this invocation, here are the assignments to meta-variables: 110 // 111 // |---------------|------------| 112 // | Meta-variable | Assignment | 113 // |---------------|------------| 114 // | $constname | N | 115 // | $constty | usize | 116 // | $tyvar | T | 117 // | $optbound | Sized | 118 // | $bound | Copy | 119 // | $trait | Clone | 120 // | $ty | Foo<T> | 121 // |---------------|------------| 122 // 123 // The following arm has the same behavior with the exception of the lack of 124 // support for a leading `const` parameter. 125 ( 126 $(#[$attr:meta])* 127 const $constname:ident : $constty:ident $(,)? 128 $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* 129 => $trait:ident for $ty:ty $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? 130 ) => { 131 unsafe_impl!( 132 @inner 133 $(#[$attr])* 134 @const $constname: $constty, 135 $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)* 136 => $trait for $ty $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)? 137 ); 138 }; 139 ( 140 $(#[$attr:meta])* 141 $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* 142 => $trait:ident for $ty:ty $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? 143 ) => { 144 unsafe_impl!( 145 @inner 146 $(#[$attr])* 147 $($tyvar $(: $(? $optbound +)* + $($bound +)*)?,)* 148 => $trait for $ty $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)? 149 ); 150 }; 151 ( 152 @inner 153 $(#[$attr:meta])* 154 $(@const $constname:ident : $constty:ident,)* 155 $($tyvar:ident $(: $(? $optbound:ident +)* + $($bound:ident +)* )?,)* 156 => $trait:ident for $ty:ty $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? 157 ) => { 158 $(#[$attr])* 159 #[allow(non_local_definitions)] 160 unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),* $(, const $constname: $constty,)*> $trait for $ty { 161 unsafe_impl!(@method $trait $(; |$candidate: $(MaybeAligned<$ref_repr>)? $(Maybe<$ptr_repr>)?| $is_bit_valid)?); 162 } 163 }; 164 165 (@method TryFromBytes ; |$candidate:ident: MaybeAligned<$repr:ty>| $is_bit_valid:expr) => { 166 #[allow(clippy::missing_inline_in_public_items)] 167 #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] 168 fn only_derive_is_allowed_to_implement_this_trait() {} 169 170 #[inline] 171 fn is_bit_valid<AA: crate::pointer::invariant::Reference>(candidate: Maybe<'_, Self, AA>) -> bool { 172 // SAFETY: 173 // - The cast preserves address. The caller has promised that the 174 // cast results in an object of equal or lesser size, and so the 175 // cast returns a pointer which references a subset of the bytes 176 // of `p`. 177 // - The cast preserves provenance. 178 // - The caller has promised that the destination type has 179 // `UnsafeCell`s at the same byte ranges as the source type. 180 #[allow(clippy::as_conversions)] 181 let candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| p as *mut _) }; 182 183 // SAFETY: The caller has promised that the referenced memory region 184 // will contain a valid `$repr`. 185 let $candidate = unsafe { candidate.assume_validity::<crate::pointer::invariant::Valid>() }; 186 $is_bit_valid 187 } 188 }; 189 (@method TryFromBytes ; |$candidate:ident: Maybe<$repr:ty>| $is_bit_valid:expr) => { 190 #[allow(clippy::missing_inline_in_public_items)] 191 #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] 192 fn only_derive_is_allowed_to_implement_this_trait() {} 193 194 #[inline] 195 fn is_bit_valid<AA: crate::pointer::invariant::Reference>(candidate: Maybe<'_, Self, AA>) -> bool { 196 // SAFETY: 197 // - The cast preserves address. The caller has promised that the 198 // cast results in an object of equal or lesser size, and so the 199 // cast returns a pointer which references a subset of the bytes 200 // of `p`. 201 // - The cast preserves provenance. 202 // - The caller has promised that the destination type has 203 // `UnsafeCell`s at the same byte ranges as the source type. 204 #[allow(clippy::as_conversions)] 205 let $candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| p as *mut _) }; 206 207 // Restore the invariant that the referent bytes are initialized. 208 // SAFETY: The above cast does not uninitialize any referent bytes; 209 // they remain initialized. 210 let $candidate = unsafe { $candidate.assume_validity::<crate::pointer::invariant::Initialized>() }; 211 212 $is_bit_valid 213 } 214 }; 215 (@method TryFromBytes) => { 216 #[allow(clippy::missing_inline_in_public_items)] 217 #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] 218 fn only_derive_is_allowed_to_implement_this_trait() {} 219 #[inline(always)] fn is_bit_valid<AA: crate::pointer::invariant::Reference>(_: Maybe<'_, Self, AA>) -> bool { true } 220 }; 221 (@method $trait:ident) => { 222 #[allow(clippy::missing_inline_in_public_items)] 223 #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] 224 fn only_derive_is_allowed_to_implement_this_trait() {} 225 }; 226 (@method $trait:ident; |$_candidate:ident $(: &$_ref_repr:ty)? $(: NonNull<$_ptr_repr:ty>)?| $_is_bit_valid:expr) => { 227 compile_error!("Can't provide `is_bit_valid` impl for trait other than `TryFromBytes`"); 228 }; 229 } 230 231 /// Implements `$trait` for a type which implements `TransparentWrapper`. 232 /// 233 /// Calling this macro is safe; the internals of the macro emit appropriate 234 /// trait bounds which ensure that the given impl is sound. 235 macro_rules! impl_for_transparent_wrapper { 236 ( 237 $(#[$attr:meta])* 238 $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?)? 239 => $trait:ident for $ty:ty $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? 240 ) => { 241 $(#[$attr])* 242 #[allow(non_local_definitions)] 243 244 // This block implements `$trait` for `$ty` under the following 245 // conditions: 246 // - `$ty: TransparentWrapper` 247 // - `$ty::Inner: $trait` 248 // - For some `Xxx`, `$ty::XxxVariance = Covariant` (`Xxx` is determined 249 // by the `@define_is_transparent_wrapper` macro arms). This bound 250 // ensures that some layout property is the same between `$ty` and 251 // `$ty::Inner`. Which layout property this is depends on the trait 252 // being implemented (for example, `FromBytes` is not concerned with 253 // alignment, but is concerned with bit validity). 254 // 255 // In other words, `$ty` is guaranteed to soundly implement `$trait` 256 // because some property of its layout is the same as `$ty::Inner`, 257 // which implements `$trait`. Most of the complexity in this macro is to 258 // ensure that the above-mentioned conditions are actually met, and that 259 // the proper variance (ie, the proper layout property) is chosen. 260 261 // SAFETY: 262 // - `is_transparent_wrapper<I, W>` requires: 263 // - `W: TransparentWrapper<I>` 264 // - `W::Inner: $trait` 265 // - `f` is generic over `I: Invariants`, and in its body, calls 266 // `is_transparent_wrapper::<I, $ty>()`. Thus, this code will only 267 // compile if, for all `I: Invariants`: 268 // - `$ty: TransparentWrapper<I>` 269 // - `$ty::Inner: $trait` 270 // 271 // These two facts - that `$ty: TransparentWrapper<I>` and that 272 // `$ty::Inner: $trait` - are the preconditions to the full safety 273 // proofs, which are completed below in the 274 // `@define_is_transparent_wrapper` macro arms. The safety proof is 275 // slightly different for each trait. 276 unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?> $trait for $ty { 277 #[allow(dead_code, clippy::missing_inline_in_public_items)] 278 #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] 279 fn only_derive_is_allowed_to_implement_this_trait() { 280 use crate::{pointer::invariant::Invariants, util::*}; 281 282 impl_for_transparent_wrapper!(@define_is_transparent_wrapper $trait); 283 284 #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] 285 fn f<I: Invariants, $($tyvar $(: $(? $optbound +)* $($bound +)*)?)?>() { 286 is_transparent_wrapper::<I, $ty>(); 287 } 288 } 289 290 impl_for_transparent_wrapper!( 291 @is_bit_valid 292 $(<$tyvar $(: $(? $optbound +)* $($bound +)*)?>)? 293 $trait for $ty 294 ); 295 } 296 }; 297 (@define_is_transparent_wrapper Immutable) => { 298 // SAFETY: `W: TransparentWrapper<UnsafeCellVariance = Covariant>` 299 // requires that `W` has `UnsafeCell`s at the same byte offsets as 300 // `W::Inner`. `W::Inner: Immutable` implies that `W::Inner` does not 301 // contain any `UnsafeCell`s, and so `W` does not contain any 302 // `UnsafeCell`s. Since `W = $ty`, `$ty` can soundly implement 303 // `Immutable`. 304 impl_for_transparent_wrapper!(@define_is_transparent_wrapper Immutable, UnsafeCellVariance) 305 }; 306 (@define_is_transparent_wrapper FromZeros) => { 307 // SAFETY: `W: TransparentWrapper<ValidityVariance = Covariant>` 308 // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: 309 // FromZeros` implies that the all-zeros bit pattern is a bit-valid 310 // instance of `W::Inner`, and so the all-zeros bit pattern is a 311 // bit-valid instance of `W`. Since `W = $ty`, `$ty` can soundly 312 // implement `FromZeros`. 313 impl_for_transparent_wrapper!(@define_is_transparent_wrapper FromZeros, ValidityVariance) 314 }; 315 (@define_is_transparent_wrapper FromBytes) => { 316 // SAFETY: `W: TransparentWrapper<ValidityVariance = Covariant>` 317 // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: 318 // FromBytes` implies that any initialized bit pattern is a bit-valid 319 // instance of `W::Inner`, and so any initialized bit pattern is a 320 // bit-valid instance of `W`. Since `W = $ty`, `$ty` can soundly 321 // implement `FromBytes`. 322 impl_for_transparent_wrapper!(@define_is_transparent_wrapper FromBytes, ValidityVariance) 323 }; 324 (@define_is_transparent_wrapper IntoBytes) => { 325 // SAFETY: `W: TransparentWrapper<ValidityVariance = Covariant>` 326 // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: 327 // IntoBytes` implies that no bit-valid instance of `W::Inner` contains 328 // uninitialized bytes, and so no bit-valid instance of `W` contains 329 // uninitialized bytes. Since `W = $ty`, `$ty` can soundly implement 330 // `IntoBytes`. 331 impl_for_transparent_wrapper!(@define_is_transparent_wrapper IntoBytes, ValidityVariance) 332 }; 333 (@define_is_transparent_wrapper Unaligned) => { 334 // SAFETY: `W: TransparentWrapper<AlignmentVariance = Covariant>` 335 // requires that `W` has the same alignment as `W::Inner`. `W::Inner: 336 // Unaligned` implies `W::Inner`'s alignment is 1, and so `W`'s 337 // alignment is 1. Since `W = $ty`, `W` can soundly implement 338 // `Unaligned`. 339 impl_for_transparent_wrapper!(@define_is_transparent_wrapper Unaligned, AlignmentVariance) 340 }; 341 (@define_is_transparent_wrapper TryFromBytes) => { 342 // SAFETY: `W: TransparentWrapper<ValidityVariance = Covariant>` 343 // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: 344 // TryFromBytes` implies that `<W::Inner as 345 // TryFromBytes>::is_bit_valid(c)` only returns `true` if `c` references 346 // a bit-valid instance of `W::Inner`. Thus, `<W::Inner as 347 // TryFromBytes>::is_bit_valid(c)` only returns `true` if `c` references 348 // a bit-valid instance of `W`. Below, we implement `<W as 349 // TryFromBytes>::is_bit_valid` by deferring to `<W::Inner as 350 // TryFromBytes>::is_bit_valid`. Since `W = $ty`, it is sound for `$ty` 351 // to implement `TryFromBytes` with this implementation of 352 // `is_bit_valid`. 353 impl_for_transparent_wrapper!(@define_is_transparent_wrapper TryFromBytes, ValidityVariance) 354 }; 355 (@define_is_transparent_wrapper $trait:ident, $variance:ident) => { 356 #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] 357 fn is_transparent_wrapper<I: Invariants, W: TransparentWrapper<I, $variance = Covariant> + ?Sized>() 358 where 359 W::Inner: $trait, 360 {} 361 }; 362 ( 363 @is_bit_valid 364 $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)? 365 TryFromBytes for $ty:ty 366 ) => { 367 // SAFETY: See safety comment in `(@define_is_transparent_wrapper 368 // TryFromBytes)` macro arm for an explanation of why this is a sound 369 // implementation of `is_bit_valid`. 370 #[inline] 371 fn is_bit_valid<A: crate::pointer::invariant::Reference>(candidate: Maybe<'_, Self, A>) -> bool { 372 TryFromBytes::is_bit_valid(candidate.transparent_wrapper_into_inner()) 373 } 374 }; 375 ( 376 @is_bit_valid 377 $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)? 378 $trait:ident for $ty:ty 379 ) => { 380 // Trait other than `TryFromBytes`; no `is_bit_valid` impl. 381 }; 382 } 383 384 /// Implements a trait for a type, bounding on each memeber of the power set of 385 /// a set of type variables. This is useful for implementing traits for tuples 386 /// or `fn` types. 387 /// 388 /// The last argument is the name of a macro which will be called in every 389 /// `impl` block, and is expected to expand to the name of the type for which to 390 /// implement the trait. 391 /// 392 /// For example, the invocation: 393 /// ```ignore 394 /// unsafe_impl_for_power_set!(A, B => Foo for type!(...)) 395 /// ``` 396 /// ...expands to: 397 /// ```ignore 398 /// unsafe impl Foo for type!() { ... } 399 /// unsafe impl<B> Foo for type!(B) { ... } 400 /// unsafe impl<A, B> Foo for type!(A, B) { ... } 401 /// ``` 402 macro_rules! unsafe_impl_for_power_set { 403 ( 404 $first:ident $(, $rest:ident)* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...) 405 $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? 406 ) => { 407 unsafe_impl_for_power_set!( 408 $($rest),* $(-> $ret)? => $trait for $macro!(...) 409 $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)? 410 ); 411 unsafe_impl_for_power_set!( 412 @impl $first $(, $rest)* $(-> $ret)? => $trait for $macro!(...) 413 $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)? 414 ); 415 }; 416 ( 417 $(-> $ret:ident)? => $trait:ident for $macro:ident!(...) 418 $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? 419 ) => { 420 unsafe_impl_for_power_set!( 421 @impl $(-> $ret)? => $trait for $macro!(...) 422 $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)? 423 ); 424 }; 425 ( 426 @impl $($vars:ident),* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...) 427 $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? 428 ) => { 429 unsafe_impl!( 430 $($vars,)* $($ret)? => $trait for $macro!($($vars),* $(-> $ret)?) 431 $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)? 432 ); 433 }; 434 } 435 436 /// Expands to an `Option<extern "C" fn>` type with the given argument types and 437 /// return type. Designed for use with `unsafe_impl_for_power_set`. 438 macro_rules! opt_extern_c_fn { 439 ($($args:ident),* -> $ret:ident) => { Option<extern "C" fn($($args),*) -> $ret> }; 440 } 441 442 /// Expands to a `Option<fn>` type with the given argument types and return 443 /// type. Designed for use with `unsafe_impl_for_power_set`. 444 macro_rules! opt_fn { 445 ($($args:ident),* -> $ret:ident) => { Option<fn($($args),*) -> $ret> }; 446 } 447 448 /// Implements trait(s) for a type or verifies the given implementation by 449 /// referencing an existing (derived) implementation. 450 /// 451 /// This macro exists so that we can provide zerocopy-derive as an optional 452 /// dependency and still get the benefit of using its derives to validate that 453 /// our trait impls are sound. 454 /// 455 /// When compiling without `--cfg 'feature = "derive"` and without `--cfg test`, 456 /// `impl_or_verify!` emits the provided trait impl. When compiling with either 457 /// of those cfgs, it is expected that the type in question is deriving the 458 /// traits instead. In this case, `impl_or_verify!` emits code which validates 459 /// that the given trait impl is at least as restrictive as the the impl emitted 460 /// by the custom derive. This has the effect of confirming that the impl which 461 /// is emitted when the `derive` feature is disabled is actually sound (on the 462 /// assumption that the impl emitted by the custom derive is sound). 463 /// 464 /// The caller is still required to provide a safety comment (e.g. using the 465 /// `safety_comment!` macro) . The reason for this restriction is that, while 466 /// `impl_or_verify!` can guarantee that the provided impl is sound when it is 467 /// compiled with the appropriate cfgs, there is no way to guarantee that it is 468 /// ever compiled with those cfgs. In particular, it would be possible to 469 /// accidentally place an `impl_or_verify!` call in a context that is only ever 470 /// compiled when the `derive` feature is disabled. If that were to happen, 471 /// there would be nothing to prevent an unsound trait impl from being emitted. 472 /// Requiring a safety comment reduces the likelihood of emitting an unsound 473 /// impl in this case, and also provides useful documentation for readers of the 474 /// code. 475 /// 476 /// Finally, if a `TryFromBytes::is_bit_valid` impl is provided, it must adhere 477 /// to the safety preconditions of [`unsafe_impl!`]. 478 /// 479 /// ## Example 480 /// 481 /// ```rust,ignore 482 /// // Note that these derives are gated by `feature = "derive"` 483 /// #[cfg_attr(any(feature = "derive", test), derive(FromZeros, FromBytes, IntoBytes, Unaligned))] 484 /// #[repr(transparent)] 485 /// struct Wrapper<T>(T); 486 /// 487 /// safety_comment! { 488 /// /// SAFETY: 489 /// /// `Wrapper<T>` is `repr(transparent)`, so it is sound to implement any 490 /// /// zerocopy trait if `T` implements that trait. 491 /// impl_or_verify!(T: FromZeros => FromZeros for Wrapper<T>); 492 /// impl_or_verify!(T: FromBytes => FromBytes for Wrapper<T>); 493 /// impl_or_verify!(T: IntoBytes => IntoBytes for Wrapper<T>); 494 /// impl_or_verify!(T: Unaligned => Unaligned for Wrapper<T>); 495 /// } 496 /// ``` 497 macro_rules! impl_or_verify { 498 // The following two match arms follow the same pattern as their 499 // counterparts in `unsafe_impl!`; see the documentation on those arms for 500 // more details. 501 ( 502 const $constname:ident : $constty:ident $(,)? 503 $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* 504 => $trait:ident for $ty:ty 505 ) => { 506 impl_or_verify!(@impl { unsafe_impl!( 507 const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty 508 ); }); 509 impl_or_verify!(@verify $trait, { 510 impl<const $constname: $constty, $($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {} 511 }); 512 }; 513 ( 514 $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* 515 => $trait:ident for $ty:ty $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? 516 ) => { 517 impl_or_verify!(@impl { unsafe_impl!( 518 $($tyvar $(: $(? $optbound +)* $($bound +)*)?),* => $trait for $ty 519 $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid)? 520 ); }); 521 impl_or_verify!(@verify $trait, { 522 impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?),*> Subtrait for $ty {} 523 }); 524 }; 525 (@impl $impl_block:tt) => { 526 #[cfg(not(any(feature = "derive", test)))] 527 const _: () = { $impl_block }; 528 }; 529 (@verify $trait:ident, $impl_block:tt) => { 530 #[cfg(any(feature = "derive", test))] 531 const _: () = { 532 trait Subtrait: $trait {} 533 $impl_block 534 }; 535 }; 536 } 537 538 /// Implements `KnownLayout` for a sized type. 539 macro_rules! impl_known_layout { 540 ($(const $constvar:ident : $constty:ty, $tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => { 541 $(impl_known_layout!(@inner const $constvar: $constty, $tyvar $(: ?$optbound)? => $ty);)* 542 }; 543 ($($tyvar:ident $(: ?$optbound:ident)? => $ty:ty),* $(,)?) => { 544 $(impl_known_layout!(@inner , $tyvar $(: ?$optbound)? => $ty);)* 545 }; 546 ($($(#[$attrs:meta])* $ty:ty),*) => { $(impl_known_layout!(@inner , => $(#[$attrs])* $ty);)* }; 547 (@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $(#[$attrs:meta])* $ty:ty) => { 548 const _: () = { 549 use core::ptr::NonNull; 550 551 #[allow(non_local_definitions)] 552 $(#[$attrs])* 553 // SAFETY: Delegates safety to `DstLayout::for_type`. 554 unsafe impl<$($tyvar $(: ?$optbound)?)? $(, const $constvar : $constty)?> KnownLayout for $ty { 555 #[allow(clippy::missing_inline_in_public_items)] 556 #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] 557 fn only_derive_is_allowed_to_implement_this_trait() where Self: Sized {} 558 559 type PointerMetadata = (); 560 561 // SAFETY: `CoreMaybeUninit<T>::LAYOUT` and `T::LAYOUT` are 562 // identical because `CoreMaybeUninit<T>` has the same size and 563 // alignment as `T` [1], and `CoreMaybeUninit` admits 564 // uninitialized bytes in all positions. 565 // 566 // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: 567 // 568 // `MaybeUninit<T>` is guaranteed to have the same size, 569 // alignment, and ABI as `T` 570 type MaybeUninit = core::mem::MaybeUninit<Self>; 571 572 const LAYOUT: crate::DstLayout = crate::DstLayout::for_type::<$ty>(); 573 574 // SAFETY: `.cast` preserves address and provenance. 575 // 576 // TODO(#429): Add documentation to `.cast` that promises that 577 // it preserves provenance. 578 #[inline(always)] 579 fn raw_from_ptr_len(bytes: NonNull<u8>, _meta: ()) -> NonNull<Self> { 580 bytes.cast::<Self>() 581 } 582 583 #[inline(always)] 584 fn pointer_to_metadata(_ptr: *mut Self) -> () { 585 } 586 } 587 }; 588 }; 589 } 590 591 /// Implements `KnownLayout` for a type in terms of the implementation of 592 /// another type with the same representation. 593 /// 594 /// # Safety 595 /// 596 /// - `$ty` and `$repr` must have the same: 597 /// - Fixed prefix size 598 /// - Alignment 599 /// - (For DSTs) trailing slice element size 600 /// - It must be valid to perform an `as` cast from `*mut $repr` to `*mut $ty`, 601 /// and this operation must preserve referent size (ie, `size_of_val_raw`). 602 macro_rules! unsafe_impl_known_layout { 603 ($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($repr:ty)] $ty:ty) => { 604 const _: () = { 605 use core::ptr::NonNull; 606 607 #[allow(non_local_definitions)] 608 unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty { 609 #[allow(clippy::missing_inline_in_public_items)] 610 #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] 611 fn only_derive_is_allowed_to_implement_this_trait() {} 612 613 type PointerMetadata = <$repr as KnownLayout>::PointerMetadata; 614 type MaybeUninit = <$repr as KnownLayout>::MaybeUninit; 615 616 const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT; 617 618 // SAFETY: All operations preserve address and provenance. 619 // Caller has promised that the `as` cast preserves size. 620 // 621 // TODO(#429): Add documentation to `NonNull::new_unchecked` 622 // that it preserves provenance. 623 #[inline(always)] 624 fn raw_from_ptr_len(bytes: NonNull<u8>, meta: <$repr as KnownLayout>::PointerMetadata) -> NonNull<Self> { 625 #[allow(clippy::as_conversions)] 626 let ptr = <$repr>::raw_from_ptr_len(bytes, meta).as_ptr() as *mut Self; 627 // SAFETY: `ptr` was converted from `bytes`, which is non-null. 628 unsafe { NonNull::new_unchecked(ptr) } 629 } 630 631 #[inline(always)] 632 fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata { 633 #[allow(clippy::as_conversions)] 634 let ptr = ptr as *mut $repr; 635 <$repr>::pointer_to_metadata(ptr) 636 } 637 } 638 }; 639 }; 640 } 641 642 /// Uses `align_of` to confirm that a type or set of types have alignment 1. 643 /// 644 /// Note that `align_of<T>` requires `T: Sized`, so this macro doesn't work for 645 /// unsized types. 646 macro_rules! assert_unaligned { 647 ($($tys:ty),*) => { 648 $( 649 // We only compile this assertion under `cfg(test)` to avoid taking 650 // an extra non-dev dependency (and making this crate more expensive 651 // to compile for our dependents). 652 #[cfg(test)] 653 static_assertions::const_assert_eq!(core::mem::align_of::<$tys>(), 1); 654 )* 655 }; 656 } 657 658 /// Emits a function definition as either `const fn` or `fn` depending on 659 /// whether the current toolchain version supports `const fn` with generic trait 660 /// bounds. 661 macro_rules! maybe_const_trait_bounded_fn { 662 // This case handles both `self` methods (where `self` is by value) and 663 // non-method functions. Each `$args` may optionally be followed by `: 664 // $arg_tys:ty`, which can be omitted for `self`. 665 ($(#[$attr:meta])* $vis:vis const fn $name:ident($($args:ident $(: $arg_tys:ty)?),* $(,)?) $(-> $ret_ty:ty)? $body:block) => { 666 #[cfg(zerocopy_generic_bounds_in_const_fn_1_61_0)] 667 $(#[$attr])* $vis const fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body 668 669 #[cfg(not(zerocopy_generic_bounds_in_const_fn_1_61_0))] 670 $(#[$attr])* $vis fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body 671 }; 672 } 673 674 /// Either panic (if the current Rust toolchain supports panicking in `const 675 /// fn`) or evaluate a constant that will cause an array indexing error whose 676 /// error message will include the format string. 677 /// 678 /// The type that this expression evaluates to must be `Copy`, or else the 679 /// non-panicking desugaring will fail to compile. 680 macro_rules! const_panic { 681 (@non_panic $($_arg:tt)+) => {{ 682 // This will type check to whatever type is expected based on the call 683 // site. 684 let panic: [_; 0] = []; 685 // This will always fail (since we're indexing into an array of size 0. 686 #[allow(unconditional_panic)] 687 panic[0] 688 }}; 689 ($($arg:tt)+) => {{ 690 #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] 691 panic!($($arg)+); 692 #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 693 const_panic!(@non_panic $($arg)+) 694 }}; 695 } 696 697 /// Either assert (if the current Rust toolchain supports panicking in `const 698 /// fn`) or evaluate the expression and, if it evaluates to `false`, call 699 /// `const_panic!`. This is used in place of `assert!` in const contexts to 700 /// accommodate old toolchains. 701 macro_rules! const_assert { 702 ($e:expr) => {{ 703 #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] 704 assert!($e); 705 #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 706 { 707 let e = $e; 708 if !e { 709 let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e))); 710 } 711 } 712 }}; 713 ($e:expr, $($args:tt)+) => {{ 714 #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] 715 assert!($e, $($args)+); 716 #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 717 { 718 let e = $e; 719 if !e { 720 let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e), ": ", stringify!($arg)), $($args)*); 721 } 722 } 723 }}; 724 } 725 726 /// Like `const_assert!`, but relative to `debug_assert!`. 727 macro_rules! const_debug_assert { 728 ($e:expr $(, $msg:expr)?) => {{ 729 #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] 730 debug_assert!($e $(, $msg)?); 731 #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 732 { 733 // Use this (rather than `#[cfg(debug_assertions)]`) to ensure that 734 // `$e` is always compiled even if it will never be evaluated at 735 // runtime. 736 if cfg!(debug_assertions) { 737 let e = $e; 738 if !e { 739 let _: () = const_panic!(@non_panic concat!("assertion failed: ", stringify!($e) $(, ": ", $msg)?)); 740 } 741 } 742 } 743 }} 744 } 745 746 /// Either invoke `unreachable!()` or `loop {}` depending on whether the Rust 747 /// toolchain supports panicking in `const fn`. 748 macro_rules! const_unreachable { 749 () => {{ 750 #[cfg(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0)] 751 unreachable!(); 752 753 #[cfg(not(zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))] 754 loop {} 755 }}; 756 } 757 758 /// Asserts at compile time that `$condition` is true for `Self` or the given 759 /// `$tyvar`s. Unlike `const_assert`, this is *strictly* a compile-time check; 760 /// it cannot be evaluated in a runtime context. The condition is checked after 761 /// monomorphization and, upon failure, emits a compile error. 762 macro_rules! static_assert { 763 (Self $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )? => $condition:expr $(, $args:tt)*) => {{ 764 trait StaticAssert { 765 const ASSERT: bool; 766 } 767 768 impl<T $(: $(? $optbound +)* $($bound +)*)?> StaticAssert for T { 769 const ASSERT: bool = { 770 const_assert!($condition $(, $args)*); 771 $condition 772 }; 773 } 774 775 const_assert!(<Self as StaticAssert>::ASSERT); 776 }}; 777 ($($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?),* => $condition:expr $(, $args:tt)*) => {{ 778 trait StaticAssert { 779 const ASSERT: bool; 780 } 781 782 impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?,)*> StaticAssert for ($($tyvar,)*) { 783 const ASSERT: bool = { 784 const_assert!($condition $(, $args)*); 785 $condition 786 }; 787 } 788 789 const_assert!(<($($tyvar,)*) as StaticAssert>::ASSERT); 790 }}; 791 } 792 793 /// Assert at compile time that `tyvar` does not have a zero-sized DST 794 /// component. 795 macro_rules! static_assert_dst_is_not_zst { 796 ($tyvar:ident) => {{ 797 use crate::KnownLayout; 798 static_assert!($tyvar: ?Sized + KnownLayout => { 799 let dst_is_zst = match $tyvar::LAYOUT.size_info { 800 crate::SizeInfo::Sized { .. } => false, 801 crate::SizeInfo::SliceDst(TrailingSliceLayout { elem_size, .. }) => { 802 elem_size == 0 803 } 804 }; 805 !dst_is_zst 806 }, "cannot call this method on a dynamically-sized type whose trailing slice element is zero-sized"); 807 }} 808 } 809