Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move exposed-provenance APIs into separate feature gate #118487

Merged
merged 2 commits into from
Dec 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions library/core/src/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,10 @@ impl<T: ?Sized> *const T {
/// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
///
/// If using those APIs is not possible because there is no way to preserve a pointer with the
/// required provenance, use [`expose_addr`][pointer::expose_addr] and
/// [`from_exposed_addr`][from_exposed_addr] instead. However, note that this makes
/// your code less portable and less amenable to tools that check for compliance with the Rust
/// memory model.
/// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
/// or [`expose_addr`][pointer::expose_addr] and [`from_exposed_addr`][from_exposed_addr]
/// instead. However, note that this makes your code less portable and less amenable to tools
/// that check for compliance with the Rust memory model.
///
/// On most platforms this will produce a value with the same bytes as the original
/// pointer, because all the bytes are dedicated to describing the address.
Expand Down Expand Up @@ -219,7 +219,8 @@ impl<T: ?Sized> *const T {
/// later call [`from_exposed_addr`][] to reconstitute the original pointer including its
/// provenance. (Reconstructing address space information, if required, is your responsibility.)
///
/// Using this method means that code is *not* following Strict Provenance rules. Supporting
/// Using this method means that code is *not* following [Strict
/// Provenance][../index.html#strict-provenance] rules. Supporting
/// [`from_exposed_addr`][] complicates specification and reasoning and may not be supported by
/// tools that help you to stay conformant with the Rust memory model, so it is recommended to
/// use [`addr`][pointer::addr] wherever possible.
Expand All @@ -230,13 +231,13 @@ impl<T: ?Sized> *const T {
/// side-effect which is required for [`from_exposed_addr`][] to work is typically not
/// available.
///
/// This API and its claimed semantics are part of the Strict Provenance experiment, see the
/// [module documentation][crate::ptr] for details.
/// It is unclear whether this method can be given a satisfying unambiguous specification. This
/// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance].
///
/// [`from_exposed_addr`]: from_exposed_addr
#[must_use]
#[inline(always)]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[unstable(feature = "exposed_provenance", issue = "95228")]
pub fn expose_addr(self) -> usize {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
self.cast::<()>() as usize
Expand Down
90 changes: 51 additions & 39 deletions library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,22 +312,30 @@
//! For instance, ARM explicitly supports high-bit tagging, and so CHERI on ARM inherits
//! that and should support it.
//!
//! ## Pointer-usize-pointer roundtrips and 'exposed' provenance
//! ## Exposed Provenance
//!
//! **This section is *non-normative* and is part of the [Strict Provenance] experiment.**
//! **This section is *non-normative* and is an extension to the [Strict Provenance] experiment.**
//!
//! As discussed above, pointer-usize-pointer roundtrips are not possible under [Strict Provenance].
//! However, there exists legacy Rust code that is full of such roundtrips, and legacy platform APIs
//! regularly assume that `usize` can capture all the information that makes up a pointer. There
//! also might be code that cannot be ported to Strict Provenance (which is something we would [like
//! to hear about][Strict Provenance]).
//!
//! For situations like this, there is a fallback plan, a way to 'opt out' of Strict Provenance.
//! However, note that this makes your code a lot harder to specify, and the code will not work
//! (well) with tools like [Miri] and [CHERI].
//!
//! This fallback plan is provided by the [`expose_addr`] and [`from_exposed_addr`] methods (which
//! are equivalent to `as` casts between pointers and integers). [`expose_addr`] is a lot like
//! This is by design: the goal of Strict Provenance is to provide a clear specification that we are
//! confident can be formalized unambiguously and can be subject to precise formal reasoning.
//!
//! However, there exist situations where pointer-usize-pointer roundtrips cannot be avoided, or
//! where avoiding them would require major refactoring. Legacy platform APIs also regularly assume
//! that `usize` can capture all the information that makes up a pointer. The goal of Strict
//! Provenance is not to rule out such code; the goal is to put all the *other* pointer-manipulating
//! code onto a more solid foundation. Strict Provenance is about improving the situation where
//! possible (all the code that can be written with Strict Provenance) without making things worse
//! for situations where Strict Provenance is insufficient.
//!
//! For these situations, there is a highly experimental extension to Strict Provenance called
//! *Exposed Provenance*. This extension permits pointer-usize-pointer roundtrips. However, its
//! semantics are on much less solid footing than Strict Provenance, and at this point it is not yet
//! clear where a satisfying unambiguous semantics can be defined for Exposed Provenance.
//! Furthermore, Exposed Provenance will not work (well) with tools like [Miri] and [CHERI].
//!
//! Exposed Provenance is provided by the [`expose_addr`] and [`from_exposed_addr`] methods, which
//! are meant to replace `as` casts between pointers and integers. [`expose_addr`] is a lot like
//! [`addr`], but additionally adds the provenance of the pointer to a global list of 'exposed'
//! provenances. (This list is purely conceptual, it exists for the purpose of specifying Rust but
//! is not materialized in actual executions, except in tools like [Miri].) [`from_exposed_addr`]
Expand All @@ -341,10 +349,11 @@
//! there is *no* previously 'exposed' provenance that justifies the way the returned pointer will
//! be used, the program has undefined behavior.
//!
//! Using [`expose_addr`] or [`from_exposed_addr`] (or the equivalent `as` casts) means that code is
//! Using [`expose_addr`] or [`from_exposed_addr`] (or the `as` casts) means that code is
//! *not* following Strict Provenance rules. The goal of the Strict Provenance experiment is to
//! determine whether it is possible to use Rust without [`expose_addr`] and [`from_exposed_addr`].
//! If this is successful, it would be a major win for avoiding specification complexity and to
//! determine how far one can get in Rust without the use of [`expose_addr`] and
//! [`from_exposed_addr`], and to encourage code to be written with Strict Provenance APIs only.
//! Maximizing the amount of such code is a major win for avoiding specification complexity and to
//! facilitate adoption of tools like [CHERI] and [Miri] that can be a big help in increasing the
//! confidence in (unsafe) Rust code.
//!
Expand Down Expand Up @@ -619,12 +628,12 @@ pub const fn invalid_mut<T>(addr: usize) -> *mut T {

/// Convert an address back to a pointer, picking up a previously 'exposed' provenance.
///
/// This is equivalent to `addr as *const T`. The provenance of the returned pointer is that of *any*
/// pointer that was previously exposed by passing it to [`expose_addr`][pointer::expose_addr],
/// or a `ptr as usize` cast. In addition, memory which is outside the control of the Rust abstract
/// machine (MMIO registers, for example) is always considered to be exposed, so long as this memory
/// is disjoint from memory that will be used by the abstract machine such as the stack, heap,
/// and statics.
/// This is a more rigorously specified alternative to `addr as *const T`. The provenance of the
/// returned pointer is that of *any* pointer that was previously exposed by passing it to
/// [`expose_addr`][pointer::expose_addr], or a `ptr as usize` cast. In addition, memory which is
/// outside the control of the Rust abstract machine (MMIO registers, for example) is always
/// considered to be exposed, so long as this memory is disjoint from memory that will be used by
/// the abstract machine such as the stack, heap, and statics.
///
/// If there is no 'exposed' provenance that justifies the way this pointer will be used,
/// the program has undefined behavior. In particular, the aliasing rules still apply: pointers
Expand All @@ -639,7 +648,8 @@ pub const fn invalid_mut<T>(addr: usize) -> *mut T {
/// On platforms with multiple address spaces, it is your responsibility to ensure that the
/// address makes sense in the address space that this pointer will be used with.
///
/// Using this method means that code is *not* following strict provenance rules. "Guessing" a
/// Using this function means that code is *not* following [Strict
/// Provenance][../index.html#strict-provenance] rules. "Guessing" a
/// suitable provenance complicates specification and reasoning and may not be supported by
/// tools that help you to stay conformant with the Rust memory model, so it is recommended to
/// use [`with_addr`][pointer::with_addr] wherever possible.
Expand All @@ -649,13 +659,13 @@ pub const fn invalid_mut<T>(addr: usize) -> *mut T {
/// since it is generally not possible to actually *compute* which provenance the returned
/// pointer has to pick up.
///
/// This API and its claimed semantics are part of the Strict Provenance experiment, see the
/// [module documentation][crate::ptr] for details.
/// It is unclear whether this function can be given a satisfying unambiguous specification. This
/// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance].
#[must_use]
#[inline(always)]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[unstable(feature = "exposed_provenance", issue = "95228")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[allow(fuzzy_provenance_casts)] // this *is* the strict provenance API one should use instead
#[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
pub fn from_exposed_addr<T>(addr: usize) -> *const T
where
T: Sized,
Expand All @@ -666,18 +676,20 @@ where

/// Convert an address back to a mutable pointer, picking up a previously 'exposed' provenance.
///
/// This is equivalent to `addr as *mut T`. The provenance of the returned pointer is that of *any*
/// pointer that was previously passed to [`expose_addr`][pointer::expose_addr] or a `ptr as usize`
/// cast. If there is no previously 'exposed' provenance that justifies the way this pointer will be
/// used, the program has undefined behavior. Note that there is no algorithm that decides which
/// provenance will be used. You can think of this as "guessing" the right provenance, and the guess
/// will be "maximally in your favor", in the sense that if there is any way to avoid undefined
/// behavior, then that is the guess that will be taken.
/// This is a more rigorously specified alternative to `addr as *mut T`. The provenance of the
/// returned pointer is that of *any* pointer that was previously passed to
/// [`expose_addr`][pointer::expose_addr] or a `ptr as usize` cast. If there is no previously
/// 'exposed' provenance that justifies the way this pointer will be used, the program has undefined
/// behavior. Note that there is no algorithm that decides which provenance will be used. You can
/// think of this as "guessing" the right provenance, and the guess will be "maximally in your
/// favor", in the sense that if there is any way to avoid undefined behavior, then that is the
/// guess that will be taken.
///
/// On platforms with multiple address spaces, it is your responsibility to ensure that the
/// address makes sense in the address space that this pointer will be used with.
///
/// Using this method means that code is *not* following strict provenance rules. "Guessing" a
/// Using this function means that code is *not* following [Strict
/// Provenance][../index.html#strict-provenance] rules. "Guessing" a
/// suitable provenance complicates specification and reasoning and may not be supported by
/// tools that help you to stay conformant with the Rust memory model, so it is recommended to
/// use [`with_addr`][pointer::with_addr] wherever possible.
Expand All @@ -687,13 +699,13 @@ where
/// since it is generally not possible to actually *compute* which provenance the returned
/// pointer has to pick up.
///
/// This API and its claimed semantics are part of the Strict Provenance experiment, see the
/// [module documentation][crate::ptr] for details.
/// It is unclear whether this function can be given a satisfying unambiguous specification. This
/// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance].
#[must_use]
#[inline(always)]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[unstable(feature = "exposed_provenance", issue = "95228")]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
#[allow(fuzzy_provenance_casts)] // this *is* the strict provenance API one should use instead
#[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead
pub fn from_exposed_addr_mut<T>(addr: usize) -> *mut T
where
T: Sized,
Expand Down
19 changes: 10 additions & 9 deletions library/core/src/ptr/mut_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,10 @@ impl<T: ?Sized> *mut T {
/// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
///
/// If using those APIs is not possible because there is no way to preserve a pointer with the
/// required provenance, use [`expose_addr`][pointer::expose_addr] and
/// [`from_exposed_addr_mut`][from_exposed_addr_mut] instead. However, note that this makes
/// your code less portable and less amenable to tools that check for compliance with the Rust
/// memory model.
/// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
/// or [`expose_addr`][pointer::expose_addr] and [`from_exposed_addr`][from_exposed_addr]
/// instead. However, note that this makes your code less portable and less amenable to tools
/// that check for compliance with the Rust memory model.
///
/// On most platforms this will produce a value with the same bytes as the original
/// pointer, because all the bytes are dedicated to describing the address.
Expand Down Expand Up @@ -226,7 +226,8 @@ impl<T: ?Sized> *mut T {
/// later call [`from_exposed_addr_mut`][] to reconstitute the original pointer including its
/// provenance. (Reconstructing address space information, if required, is your responsibility.)
///
/// Using this method means that code is *not* following Strict Provenance rules. Supporting
/// Using this method means that code is *not* following [Strict
/// Provenance][../index.html#strict-provenance] rules. Supporting
/// [`from_exposed_addr_mut`][] complicates specification and reasoning and may not be supported
/// by tools that help you to stay conformant with the Rust memory model, so it is recommended
/// to use [`addr`][pointer::addr] wherever possible.
Expand All @@ -237,13 +238,13 @@ impl<T: ?Sized> *mut T {
/// side-effect which is required for [`from_exposed_addr_mut`][] to work is typically not
/// available.
///
/// This API and its claimed semantics are part of the Strict Provenance experiment, see the
/// [module documentation][crate::ptr] for details.
/// It is unclear whether this method can be given a satisfying unambiguous specification. This
/// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance].
///
/// [`from_exposed_addr_mut`]: from_exposed_addr_mut
#[must_use]
#[inline(always)]
#[unstable(feature = "strict_provenance", issue = "95228")]
#[unstable(feature = "exposed_provenance", issue = "95228")]
pub fn expose_addr(self) -> usize {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
self.cast::<()>() as usize
Expand All @@ -259,7 +260,7 @@ impl<T: ?Sized> *mut T {
/// This is equivalent to using [`wrapping_offset`][pointer::wrapping_offset] to offset
/// `self` to the given address, and therefore has all the same capabilities and restrictions.
///
/// This API and its claimed semantics are part of the Strict Provenance experiment,
/// This API and its claimed semantics are an extension to the Strict Provenance experiment,
/// see the [module documentation][crate::ptr] for details.
#[must_use]
#[inline]
Expand Down
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@
#![feature(error_iter)]
#![feature(exact_size_is_empty)]
#![feature(exclusive_wrapper)]
#![feature(exposed_provenance)]
#![feature(extend_one)]
#![feature(float_gamma)]
#![feature(float_minimum_maximum)]
Expand Down
2 changes: 1 addition & 1 deletion src/tools/miri/tests/fail/provenance/ptr_int_unexposed.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@compile-flags: -Zmiri-permissive-provenance
#![feature(strict_provenance)]
#![feature(strict_provenance, exposed_provenance)]

fn main() {
let x: i32 = 3;
Expand Down
2 changes: 1 addition & 1 deletion src/tools/miri/tests/fail/provenance/ptr_invalid.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(strict_provenance)]
#![feature(strict_provenance, exposed_provenance)]

// Ensure that a `ptr::invalid` ptr is truly invalid.
fn main() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@compile-flags: -Zmiri-strict-provenance
#![feature(strict_provenance)]
#![feature(exposed_provenance)]

fn main() {
let addr = &0 as *const i32 as usize;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@compile-flags: -Zmiri-permissive-provenance
#![feature(strict_provenance)]
#![feature(exposed_provenance)]

// If we have only exposed read-only pointers, doing a write through a wildcard ptr should fail.

Expand Down
2 changes: 1 addition & 1 deletion src/tools/miri/tests/pass/ptr_int_from_exposed.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//@revisions: stack tree
//@[tree]compile-flags: -Zmiri-tree-borrows
//@compile-flags: -Zmiri-permissive-provenance
#![feature(strict_provenance)]
#![feature(strict_provenance, exposed_provenance)]

use std::ptr;

Expand Down
2 changes: 1 addition & 1 deletion src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@compile-flags: -Zmiri-permissive-provenance
#![feature(strict_provenance)]
#![feature(exposed_provenance)]
use std::ptr;

// Just to make sure that casting a ref to raw, to int and back to raw
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@compile-flags: -Zmiri-permissive-provenance
#![feature(strict_provenance)]
#![feature(exposed_provenance)]

use std::ptr;

Expand Down
Loading