Skip to content

Commit 5870ed6

Browse files
committed
[pointer][invariant] Move to separate file
This prepares us for future changes which will significantly increase the amount of code in the `invariant` module. Also merge `aliasing_safety` into this new file.
1 parent 620e6ce commit 5870ed6

File tree

4 files changed

+232
-237
lines changed

4 files changed

+232
-237
lines changed

src/pointer/aliasing_safety.rs

Lines changed: 0 additions & 89 deletions
This file was deleted.

src/pointer/invariant.rs

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
// Copyright 2024 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+
#![allow(missing_copy_implementations, missing_debug_implementations)]
10+
11+
//! The parameterized invariants of a [`Ptr`][super::Ptr].
12+
//!
13+
//! Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`])
14+
//! triples implementing the [`Invariants`] trait.
15+
16+
/// The invariants of a [`Ptr`][super::Ptr].
17+
pub trait Invariants: Sealed {
18+
type Aliasing: Aliasing;
19+
type Alignment: Alignment;
20+
type Validity: Validity;
21+
}
22+
23+
impl<A: Aliasing, AA: Alignment, V: Validity> Invariants for (A, AA, V) {
24+
type Aliasing = A;
25+
type Alignment = AA;
26+
type Validity = V;
27+
}
28+
29+
/// The aliasing invariant of a [`Ptr`][super::Ptr].
30+
pub trait Aliasing: Sealed {
31+
/// Is `Self` [`Exclusive`]?
32+
#[doc(hidden)]
33+
const IS_EXCLUSIVE: bool;
34+
}
35+
36+
/// The alignment invariant of a [`Ptr`][super::Ptr].
37+
pub trait Alignment: Sealed {}
38+
39+
/// The validity invariant of a [`Ptr`][super::Ptr].
40+
pub trait Validity: Sealed {}
41+
42+
/// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`].
43+
///
44+
/// # Safety
45+
///
46+
/// Given `A: Reference`, callers may assume that either `A = Shared` or `A =
47+
/// Exclusive`.
48+
pub trait Reference: Aliasing + Sealed {}
49+
50+
/// No requirement - any invariant is allowed.
51+
pub enum Any {}
52+
impl Aliasing for Any {
53+
const IS_EXCLUSIVE: bool = false;
54+
}
55+
impl Alignment for Any {}
56+
impl Validity for Any {}
57+
58+
/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`.
59+
///
60+
/// The referent of a shared-aliased `Ptr` may be concurrently referenced by any
61+
/// number of shared-aliased `Ptr` or `&T` references, and may not be
62+
/// concurrently referenced by any exclusively-aliased `Ptr`s or `&mut T`
63+
/// references. The referent must not be mutated, except via [`UnsafeCell`]s.
64+
///
65+
/// [`UnsafeCell`]: core::cell::UnsafeCell
66+
pub enum Shared {}
67+
impl Aliasing for Shared {
68+
const IS_EXCLUSIVE: bool = false;
69+
}
70+
impl Reference for Shared {}
71+
72+
/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`.
73+
///
74+
/// The referent of an exclusively-aliased `Ptr` may not be concurrently
75+
/// referenced by any other `Ptr`s or references, and may not be accessed (read
76+
/// or written) other than via this `Ptr`.
77+
pub enum Exclusive {}
78+
impl Aliasing for Exclusive {
79+
const IS_EXCLUSIVE: bool = true;
80+
}
81+
impl Reference for Exclusive {}
82+
83+
/// The referent is aligned: for `Ptr<T>`, the referent's address is a multiple
84+
/// of the `T`'s alignment.
85+
pub enum Aligned {}
86+
impl Alignment for Aligned {}
87+
88+
/// The byte ranges initialized in `T` are also initialized in the referent.
89+
///
90+
/// Formally: uninitialized bytes may only be present in `Ptr<T>`'s referent
91+
/// where they are guaranteed to be present in `T`. This is a dynamic property:
92+
/// if, at a particular byte offset, a valid enum discriminant is set, the
93+
/// subsequent bytes may only have uninitialized bytes as specificed by the
94+
/// corresponding enum.
95+
///
96+
/// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in
97+
/// the range `[0, len)`:
98+
/// - If, in any instance `t: T` of length `len`, the byte at offset `b` in `t`
99+
/// is initialized, then the byte at offset `b` within `*ptr` must be
100+
/// initialized.
101+
/// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` be
102+
/// the subset of valid instances of `T` of length `len` which contain `c` in
103+
/// the offset range `[0, b)`. If, in any instance of `t: T` in `S`, the byte
104+
/// at offset `b` in `t` is initialized, then the byte at offset `b` in `*ptr`
105+
/// must be initialized.
106+
///
107+
/// Pragmatically, this means that if `*ptr` is guaranteed to contain an enum
108+
/// type at a particular offset, and the enum discriminant stored in `*ptr`
109+
/// corresponds to a valid variant of that enum type, then it is guaranteed
110+
/// that the appropriate bytes of `*ptr` are initialized as defined by that
111+
/// variant's bit validity (although note that the variant may contain another
112+
/// enum type, in which case the same rules apply depending on the state of
113+
/// its discriminant, and so on recursively).
114+
pub enum AsInitialized {}
115+
impl Validity for AsInitialized {}
116+
117+
/// The byte ranges in the referent are fully initialized. In other words, if
118+
/// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`.
119+
pub enum Initialized {}
120+
impl Validity for Initialized {}
121+
122+
/// The referent is bit-valid for `T`.
123+
pub enum Valid {}
124+
impl Validity for Valid {}
125+
126+
pub mod aliasing_safety {
127+
use super::*;
128+
use crate::Immutable;
129+
130+
/// Pointer conversions which do not violate aliasing.
131+
///
132+
/// `U: AliasingSafe<T, A, R>` implies that a pointer conversion from `T` to
133+
/// `U` does not violate the aliasing invariant, `A`. This can be because
134+
/// `A` is [`Exclusive`] or because neither `T` nor `U` permit interior
135+
/// mutability.
136+
///
137+
/// # Safety
138+
///
139+
/// `U: AliasingSafe<T, A, R>` if either of the following conditions holds:
140+
/// - `A` is [`Exclusive`]
141+
/// - `T` and `U` both implement [`Immutable`]
142+
#[doc(hidden)]
143+
pub unsafe trait AliasingSafe<T: ?Sized, A: Aliasing, R: AliasingSafeReason> {}
144+
145+
#[doc(hidden)]
146+
pub trait AliasingSafeReason: sealed::Sealed {}
147+
impl<R: AliasingSafeReason> AliasingSafeReason for (R,) {}
148+
149+
/// The conversion is safe because only one live `Ptr` or reference may exist to
150+
/// the referent bytes at a time.
151+
#[derive(Copy, Clone, Debug)]
152+
#[doc(hidden)]
153+
pub enum BecauseExclusive {}
154+
impl AliasingSafeReason for BecauseExclusive {}
155+
156+
/// The conversion is safe because no live `Ptr`s or references permit mutation.
157+
#[derive(Copy, Clone, Debug)]
158+
#[doc(hidden)]
159+
pub enum BecauseImmutable {}
160+
impl AliasingSafeReason for BecauseImmutable {}
161+
162+
/// SAFETY: `T: AliasingSafe<Exclusive, BecauseExclusive>` because for all
163+
/// `Ptr<'a, T, I>` such that `I::Aliasing = Exclusive`, there cannot exist
164+
/// other live references to the memory referenced by `Ptr`.
165+
unsafe impl<T: ?Sized, U: ?Sized> AliasingSafe<T, Exclusive, BecauseExclusive> for U {}
166+
167+
/// SAFETY: `U: AliasingSafe<T, A, BecauseNoCell>` because for all `Ptr<'a, T,
168+
/// I>` and `Ptr<'a, U, I>` such that `I::Aliasing = A`, all live references and
169+
/// live `Ptr`s agree, by invariant on `Immutable`, that the referenced bytes
170+
/// contain no `UnsafeCell`s, and thus do not permit mutation except via
171+
/// exclusive aliasing.
172+
unsafe impl<A, T: ?Sized, U: ?Sized> AliasingSafe<T, A, BecauseImmutable> for U
173+
where
174+
A: Aliasing,
175+
T: Immutable,
176+
U: Immutable,
177+
{
178+
}
179+
180+
/// This ensures that `U: AliasingSafe<T, A>` implies `T: AliasingSafe<U, A>` in
181+
/// a manner legible to rustc, which in turn means we can write simpler bounds in
182+
/// some places.
183+
///
184+
/// SAFETY: Per `U: AliasingSafe<T, A, R>`, either:
185+
/// - `A` is `Exclusive`
186+
/// - `T` and `U` both implement `Immutable`
187+
///
188+
/// Neither property depends on which of `T` and `U` are in the `Self` position
189+
/// vs the first type parameter position.
190+
unsafe impl<A, T: ?Sized, U: ?Sized, R> AliasingSafe<U, A, (R,)> for T
191+
where
192+
A: Aliasing,
193+
R: AliasingSafeReason,
194+
U: AliasingSafe<T, A, R>,
195+
{
196+
}
197+
}
198+
199+
use sealed::Sealed;
200+
mod sealed {
201+
use super::*;
202+
203+
pub trait Sealed {}
204+
205+
impl Sealed for Any {}
206+
207+
impl Sealed for Shared {}
208+
impl Sealed for Exclusive {}
209+
210+
impl Sealed for Aligned {}
211+
212+
impl Sealed for AsInitialized {}
213+
impl Sealed for Initialized {}
214+
impl Sealed for Valid {}
215+
216+
impl<A: Sealed, AA: Sealed, V: Sealed> Sealed for (A, AA, V) {}
217+
218+
impl Sealed for super::aliasing_safety::BecauseExclusive {}
219+
impl Sealed for super::aliasing_safety::BecauseImmutable {}
220+
impl<S: Sealed> Sealed for (S,) {}
221+
}

src/pointer/mod.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@
88

99
//! Abstractions over raw pointers.
1010
11-
mod aliasing_safety;
1211
mod inner;
12+
#[doc(hidden)]
13+
pub mod invariant;
1314
mod ptr;
1415

15-
pub use aliasing_safety::{AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable};
16-
pub use ptr::{invariant, Ptr};
16+
#[doc(hidden)]
17+
pub use invariant::aliasing_safety::{
18+
AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable,
19+
};
20+
#[doc(hidden)]
21+
pub use ptr::Ptr;
1722

1823
use crate::Unaligned;
1924

0 commit comments

Comments
 (0)