Skip to content

Commit 0ccf1e2

Browse files
committed
[proofs] Initial commit
Add axioms and lemmas which are useful in proving the soundness of some trait impls. Makes progress on #429
1 parent 57c8fd9 commit 0ccf1e2

File tree

2 files changed

+120
-30
lines changed

2 files changed

+120
-30
lines changed

src/lib.rs

+20-30
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ mod macros;
243243
pub mod byteorder;
244244
#[doc(hidden)]
245245
pub mod macro_util;
246+
mod proof_utils;
246247
mod util;
247248
// TODO(#252): If we make this pub, come up with a better name.
248249
mod wrappers;
@@ -2303,17 +2304,18 @@ safety_comment! {
23032304
}
23042305
safety_comment! {
23052306
/// SAFETY:
2306-
/// `Wrapping<T>` is guaranteed by its docs [1] to have the same layout as
2307-
/// `T`. Also, `Wrapping<T>` is `#[repr(transparent)]`, and has a single
2308-
/// field, which is `pub`. Per the reference [2], this means that the
2309-
/// `#[repr(transparent)]` attribute is "considered part of the public ABI".
2307+
/// `Wrapping<T>` is `#[repr(transparent)]` and has a single `T` field,
2308+
/// which is `pub`. [1] Per axiom-repr-transparent-layout-validity, we may
2309+
/// take this to imply that `Wrapping<T>: transparent-layout-validity(T)`.
2310+
/// This is bolstered by [2]. Per lemma-repr-transparent-zerocopy-traits, if
2311+
/// `T` satisfies the safety preconditions of `FromZeroes`, `FromBytes`,
2312+
/// `AsBytes`, or `Unaligned`, then `Wrapping<T>` does too (respectively).
23102313
///
2311-
/// TODO(#429): Add quotes from documentation.
2314+
/// [1] https://doc.rust-lang.org/core/num/struct.Wrapping.html
23122315
///
2313-
/// [1] TODO(https://doc.rust-lang.org/nightly/core/num/struct.Wrapping.html#layout-1):
2314-
/// Reference this documentation once it's available on stable.
2316+
/// [2] Per https://doc.rust-lang.org/nightly/core/num/struct.Wrapping.html:
23152317
///
2316-
/// [2] https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
2318+
/// `Wrapping<T>` is guaranteed to have the same layout and ABI as `T`.
23172319
unsafe_impl!(T: FromZeroes => FromZeroes for Wrapping<T>);
23182320
unsafe_impl!(T: FromBytes => FromBytes for Wrapping<T>);
23192321
unsafe_impl!(T: AsBytes => AsBytes for Wrapping<T>);
@@ -2347,31 +2349,19 @@ safety_comment! {
23472349
}
23482350
safety_comment! {
23492351
/// SAFETY:
2350-
/// `ManuallyDrop` has the same layout and bit validity as `T` [1], and
2351-
/// accessing the inner value is safe (meaning that it's unsound to leave
2352-
/// the inner value uninitialized while exposing the `ManuallyDrop` to safe
2353-
/// code).
2354-
/// - `FromZeroes`, `FromBytes`: Since it has the same layout as `T`, any
2355-
/// valid `T` is a valid `ManuallyDrop<T>`. If `T: FromZeroes`, a sequence
2356-
/// of zero bytes is a valid `T`, and thus a valid `ManuallyDrop<T>`. If
2357-
/// `T: FromBytes`, any sequence of bytes is a valid `T`, and thus a valid
2358-
/// `ManuallyDrop<T>`.
2359-
/// - `AsBytes`: Since it has the same layout as `T`, and since it's unsound
2360-
/// to let safe code access a `ManuallyDrop` whose inner value is
2361-
/// uninitialized, safe code can only ever access a `ManuallyDrop` whose
2362-
/// contents are a valid `T`. Since `T: AsBytes`, this means that safe
2363-
/// code can only ever access a `ManuallyDrop` with all initialized bytes.
2364-
/// - `Unaligned`: `ManuallyDrop` has the same layout (and thus alignment)
2365-
/// as `T`, and `T: Unaligned` guarantees that that alignment is 1.
2366-
///
2367-
/// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
2368-
/// validity as `T`
2352+
/// `ManuallyDrop<T>` has the same layout and bit validity as `T` [1]. Per
2353+
/// axiom-transparent-layout-validity, we may use this to assume that
2354+
/// `ManuallyDrop<T>: transparent-layout-validity(T)`. Per
2355+
/// lemma-repr-transparent-zerocopy-traits, if `T` satisfies the safety
2356+
/// preconditions of `FromZeroes`, `FromBytes`, `AsBytes`, or `Unaligned`,
2357+
/// then `ManuallyDrop<T>` does too (respectively).
23692358
///
23702359
/// [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html:
23712360
///
2372-
/// TODO(#429):
2373-
/// - Add quotes from docs.
2374-
/// - Once [1] (added in
2361+
/// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
2362+
/// validity as `T`.
2363+
///
2364+
/// TODO(#429): Once [1] (added in
23752365
/// https://github.com/rust-lang/rust/pull/115522) is available on stable,
23762366
/// quote the stable docs instead of the nightly docs.
23772367
unsafe_impl!(T: ?Sized + FromZeroes => FromZeroes for ManuallyDrop<T>);

src/proof_utils.rs

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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+
//! This module exists to hold this doc comment, which provides lemmas which can
10+
//! be used in soundness proofs.
11+
//!
12+
//! # Definitions
13+
//!
14+
//! ## transparent-layout-validity
15+
//!
16+
//! A type, `T`, has the property `transparent-layout-validity(U)` if the
17+
//! following all hold:
18+
//! - `T` and `U` have the same alignment
19+
//! - For all `t: *const T`, `let u = t as *const U` is valid and
20+
//! `size_of_val_raw(t) == size_of_val_raw(u)`.
21+
//! - For all `u: *const U`, `let t = *const T` is valid and `size_of_val_raw(u)
22+
//! == size_of_val_raw(t)`.
23+
//! - For all `(t, u): (*const T, *const U)` where `size_of_val_raw(t) ==
24+
//! size_of_val_raw(u)`:
25+
//! - `t` and `u` refer to `UnsafeCell`s at the same byte ranges.
26+
//! - If `*t` contains a valid `T`, that implies that `*u` contains a valid
27+
//! `U`.
28+
//! - If `*u` contains a valid `U`, that implies that `*t` contains a valid
29+
//! `T`.
30+
//!
31+
//! # Axioms
32+
//!
33+
//! These are statements which are not technically logically bulletproof, but
34+
//! capture the way that language is used in practice in the Rust Reference and
35+
//! standard library documentation.
36+
//!
37+
//! ## axiom-transparent-layout-validity
38+
//!
39+
//! Given types `T` and `U`, the phrase "`T` is guaranteed to have the same
40+
//! layout and bit validity as `U`" is taken to imply that `T` has the property
41+
//! `transparent-layout-validity(U)`.
42+
//!
43+
//! The term "layout" is used in Rust documentation to refer to a type's size
44+
//! and alignment and the sizes, alignments, and byte offsets of each of the
45+
//! type's fields. In practice, phrases like the above are only ever used in
46+
//! contexts where the following additional properties also hold:
47+
//! - `T` and `U` have the same vtable kinds. `T`'s and `U`'s pointer metadata
48+
//! is such that raw pointer casts preserve size and field placement.
49+
//! - `T` and `U` have `UnsafeCell`s at the same byte ranges.
50+
//!
51+
//! ## axiom-repr-transparent-layout-validity
52+
//!
53+
//! Given types `T` and `U`, if `T` is a `#[repr(transparent)]` struct with a
54+
//! `pub` field of type `U`, and `T` does not contain any other fields, then
55+
//! `T` has the property `transparent-layout-validity(U)`.
56+
//!
57+
//! Per the [Rust Reference][repr-transparent]:
58+
//!
59+
//! > \[`repr(transparent)`\] is only considered part of the public ABI of a
60+
//! > type if either its single field is `pub`, or if its layout is documented
61+
//! > in prose.
62+
//!
63+
//! [repr-transparent]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
64+
//!
65+
//! # Lemmas
66+
//!
67+
//! ## lemma-repr-transparent-zerocopy-traits
68+
//!
69+
//! - Lemma: Given types `T` and `U` where `T` is
70+
//! `transparent-layout-validity(U)`, for each `Trait` in `FromZeroes`,
71+
//! `FromBytes`, `AsBytes`, and `Unaligned`, if `U` satisfies the safety
72+
//! preconditions of `Trait`, then `T` does as well.
73+
//! - Proof:
74+
//! - `FromZeroes`, `FromBytes`, and `AsBytes` all require that a type not
75+
//! contain any `UnsafeCell`s. `T: transparent-layout-validity(U)`
76+
//! guarantees that, for all pairs of `t: *const T` and `u: *const U` of
77+
//! equal size, `t` and `u` refer to `UnsafeCell`s at the same byte ranges.
78+
//! If `U: FromZeroes`, `U: FromBytes`, or `U: AsBytes`, no instance of `U`
79+
//! contains `UnsafeCell`s at any byte ranges. Thus, no instance of `T`
80+
//! contains `UnsafeCell`s at any byte ranges.
81+
//! - `U: FromZeroes` additionally requires that, given `u: *const U`, it is
82+
//! sound to initialize `*u` to contain all zero bytes. Since, for all `t:
83+
//! *const T` and `u: *const U` of equal size, `*t` and `*u` have equal bit
84+
//! validity, then it must also be the case that, given `t: *const T`, it is
85+
//! sound to initialize `*t` to contain all zero bytes.
86+
//! - `U: FromBytes` additionally requires that, given `u: *const U`, it is
87+
//! sound to initialize `*u` to contain any sequence of `u8`s. Since, for
88+
//! all `t: *const T` and `u: *const U` of equal size, `*t` and `*u` have
89+
//! equal bit validity, then it must also be the case that, given `t: *const
90+
//! T`, it is sound to initialize `*t` to contain any sequence of `u8`s.
91+
//! - `U: AsBytes` additionally requires that, given `u: &U`, it is sound to
92+
//! treat `t` as an immutable `[u8]` of length `size_of_val(u)`. This is
93+
//! equivalent to saying that no instance of `U` can contain bytes which are
94+
//! invalid for `u8`. Since, for all `t: *const T` and `u: *const U` of
95+
//! equal size, `*t` and `*u` have equal bit validity, then it must also be
96+
//! the case that no instance of `T` can contain bytes which are invalid for
97+
//! `u8`.
98+
//! - `U: Unaligned` requires that `U`'s alignment is 1. `T:
99+
//! transparent-layout-validity(U)` guarantees that `T`'s alignment is equal
100+
//! to `U`'s, and is thus also 1.

0 commit comments

Comments
 (0)