1 // Copyright 2019 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 // ON THE PRELUDE: All of the tests in this directory (excepting UI tests) 10 // disable the prelude via `#![no_implicit_prelude]`. This ensures that all code 11 // emitted by our derives doesn't accidentally assume that the prelude is 12 // included, which helps ensure that items are referred to by absolute path, 13 // which in turn ensures that these items can't accidentally refer to names 14 // which have been shadowed. For example, the code `x == None` could behave 15 // incorrectly if, in the scope in which the derive is invoked, `None` has been 16 // shadowed by `CONST None: Option<usize> = Some(1)`. 17 // 18 // `mod imp` allows us to import items and refer to them in this module without 19 // introducing the risk that this hides bugs in which derive-emitted code uses 20 // names which are not fully-qualified. For such a bug to manifest, it would 21 // need to be of the form `imp::Foo`, which is unlikely to happen by accident. 22 mod imp { 23 // Since this file is included in every test file, and since not every test 24 // file uses every item here, we allow unused imports to avoid generating 25 // warnings. 26 #[allow(unused)] 27 pub use { 28 ::core::{ 29 assert_eq, assert_ne, 30 cell::UnsafeCell, 31 convert::TryFrom, 32 hash, 33 marker::PhantomData, 34 mem::{ManuallyDrop, MaybeUninit}, 35 option::IntoIter, 36 prelude::v1::*, 37 primitive::*, 38 }, 39 ::std::{collections::hash_map::DefaultHasher, prelude::v1::*}, 40 ::zerocopy::*, 41 }; 42 } 43 44 // These items go in their own module (rather than the top level) for the same 45 // reason that we use `mod imp` above. See its comment for more details. 46 pub mod util { 47 /// A type that doesn't implement any zerocopy traits. 48 pub struct NotZerocopy<T = ()>(pub T); 49 50 /// A `u16` with alignment 2. 51 /// 52 /// Though `u16` has alignment 2 on some platforms, it's not guaranteed. By 53 /// contrast, `util::AU16` is guaranteed to have alignment 2. 54 #[derive( 55 super::imp::KnownLayout, 56 super::imp::Immutable, 57 super::imp::FromBytes, 58 super::imp::IntoBytes, 59 Copy, 60 Clone, 61 )] 62 #[repr(C, align(2))] 63 pub struct AU16(pub u16); 64 65 // Since we can't import these by path (ie, `util::assert_impl_all!`), use a 66 // name prefix to ensure our derive-emitted code isn't accidentally relying 67 // on `assert_impl_all!` being in scope. 68 #[macro_export] 69 macro_rules! util_assert_impl_all { 70 ($type:ty: $($trait:path),+ $(,)?) => { 71 const _: fn() = || { 72 use ::core::prelude::v1::*; 73 ::static_assertions::assert_impl_all!($type: $($trait),+); 74 }; 75 }; 76 } 77 78 // Since we can't import these by path (ie, `util::assert_not_impl_any!`), 79 // use a name prefix to ensure our derive-emitted code isn't accidentally 80 // relying on `assert_not_impl_any!` being in scope. 81 #[macro_export] 82 macro_rules! util_assert_not_impl_any { 83 ($x:ty: $($t:path),+ $(,)?) => { 84 const _: fn() = || { 85 use ::core::prelude::v1::*; 86 ::static_assertions::assert_not_impl_any!($x: $($t),+); 87 }; 88 }; 89 } 90 91 #[macro_export] 92 macro_rules! test_trivial_is_bit_valid { 93 ($x:ty => $name:ident) => { 94 #[test] 95 fn $name() { 96 util::test_trivial_is_bit_valid::<$x>(); 97 } 98 }; 99 } 100 101 // Under some circumstances, our `TryFromBytes` derive generates a trivial 102 // `is_bit_valid` impl that unconditionally returns `true`. This test 103 // attempts to validate that this is, indeed, the behavior of our 104 // `TryFromBytes` derive. It is not foolproof, but is likely to catch some 105 // mistakes. 106 // 107 // As of this writing, this happens when deriving `TryFromBytes` thanks to a 108 // top-level `#[derive(FromBytes)]`. test_trivial_is_bit_valid<T: super::imp::TryFromBytes>()109 pub fn test_trivial_is_bit_valid<T: super::imp::TryFromBytes>() { 110 // This test works based on the insight that a trivial `is_bit_valid` 111 // impl should never load any bytes from memory. Thus, while it is 112 // technically a violation of `is_bit_valid`'s safety precondition to 113 // pass a pointer to uninitialized memory, the `is_bit_valid` impl we 114 // expect our derives to generate should never touch this memory, and 115 // thus should never exhibit UB. By contrast, if our derives are 116 // spuriously generating non-trivial `is_bit_valid` impls, this should 117 // cause UB which may be caught by Miri. 118 119 let buf = super::imp::MaybeUninit::<T>::uninit(); 120 let ptr = super::imp::Ptr::from_ref(&buf); 121 // SAFETY: This is intentionally unsound; see the preceding comment. 122 let ptr = unsafe { ptr.assume_initialized() }; 123 124 // SAFETY: `T` and `MaybeUninit<T>` have the same layout, so this is a 125 // size-preserving cast. It is also a provenance-preserving cast. 126 let ptr = unsafe { ptr.cast_unsized_unchecked(|p| p as *mut T) }; 127 assert!(<T as super::imp::TryFromBytes>::is_bit_valid(ptr)); 128 } 129 } 130