• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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