Auto merge of #118487 - RalfJung:exposed-provenance, r=thomcc

move exposed-provenance APIs into separate feature gate

We have already stated explicitly for all the 'exposed' functions that

> Using this method means that code is *not* following strict provenance rules.

However, they were part of the same feature gate and still described as part of the strict provenance experiment. Unfortunately, their semantics are much less clear and certainly nowhere near stabilization, so in preparation for an attempt to stabilize the strict provenance APIs, I suggest we split the things related to "exposed" into their own feature gate. I also used this opportunity to better explain how Exposed Provenance fits into the larger plan here: this is *one possible candidate* for `as` semantics, but we don't know if it is actually viable, so we can't really promise that it is equivalent to `as`. If it works out we probably want to make `as` equivalent to the 'exposed' APIs; if it doesn't, we will remove them again and try to find some other semantics for `as`.
This commit is contained in:
bors 2023-12-03 07:04:12 +00:00
commit 71940e0a8a
11 changed files with 76 additions and 61 deletions

View File

@ -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.
@ -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.
@ -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

View File

@ -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]).
//! 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.
//!
//! 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].
//! 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.
//!
//! 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
//! 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`]
@ -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.
//!
@ -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
@ -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.
@ -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,
@ -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.
@ -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,

View File

@ -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.
@ -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.
@ -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
@ -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]

View File

@ -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)]

View File

@ -1,5 +1,5 @@
//@compile-flags: -Zmiri-permissive-provenance
#![feature(strict_provenance)]
#![feature(strict_provenance, exposed_provenance)]
fn main() {
let x: i32 = 3;

View File

@ -1,4 +1,4 @@
#![feature(strict_provenance)]
#![feature(strict_provenance, exposed_provenance)]
// Ensure that a `ptr::invalid` ptr is truly invalid.
fn main() {

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -1,5 +1,5 @@
//@compile-flags: -Zmiri-permissive-provenance
#![feature(strict_provenance)]
#![feature(exposed_provenance)]
use std::ptr;