Skip to content

Commit 7f91dbe

Browse files
authored
Rollup merge of rust-lang#130350 - RalfJung:strict-provenance, r=dtolnay
stabilize Strict Provenance and Exposed Provenance APIs Given that [RFC 3559](https://rust-lang.github.io/rfcs/3559-rust-has-provenance.html) has been accepted, t-lang has approved the concept of provenance to exist in the language. So I think it's time that we stabilize the strict provenance and exposed provenance APIs, and discuss provenance explicitly in the docs: ```rust // core::ptr pub const fn without_provenance<T>(addr: usize) -> *const T; pub const fn dangling<T>() -> *const T; pub const fn without_provenance_mut<T>(addr: usize) -> *mut T; pub const fn dangling_mut<T>() -> *mut T; pub fn with_exposed_provenance<T>(addr: usize) -> *const T; pub fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T; impl<T: ?Sized> *const T { pub fn addr(self) -> usize; pub fn expose_provenance(self) -> usize; pub fn with_addr(self, addr: usize) -> Self; pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self; } impl<T: ?Sized> *mut T { pub fn addr(self) -> usize; pub fn expose_provenance(self) -> usize; pub fn with_addr(self, addr: usize) -> Self; pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self; } impl<T: ?Sized> NonNull<T> { pub fn addr(self) -> NonZero<usize>; pub fn with_addr(self, addr: NonZero<usize>) -> Self; pub fn map_addr(self, f: impl FnOnce(NonZero<usize>) -> NonZero<usize>) -> Self; } ``` I also did a pass over the docs to adjust them, because this is no longer an "experiment". The `ptr` docs now discuss the concept of provenance in general, and then they go into the two families of APIs for dealing with provenance: Strict Provenance and Exposed Provenance. I removed the discussion of how pointers also have an associated "address space" -- that is not actually tracked in the pointer value, it is tracked in the type, so IMO it just distracts from the core point of provenance. I also adjusted the docs for `with_exposed_provenance` to make it clear that we cannot guarantee much about this function, it's all best-effort. There are two unstable lints associated with the strict_provenance feature gate; I moved them to a new [strict_provenance_lints](rust-lang#130351) feature since I didn't want this PR to have an even bigger FCP. ;) `@rust-lang/opsem` Would be great to get some feedback on the docs here. :) Nominating for `@rust-lang/libs-api.` Part of rust-lang#95228. [FCP comment](rust-lang#130350 (comment))
2 parents e2b2c3a + 6d2a437 commit 7f91dbe

File tree

17 files changed

+328
-411
lines changed

17 files changed

+328
-411
lines changed

alloc/benches/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
#![feature(iter_next_chunk)]
55
#![feature(repr_simd)]
66
#![feature(slice_partition_dedup)]
7-
#![feature(strict_provenance)]
7+
#![cfg_attr(bootstrap, feature(strict_provenance))]
8+
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
89
#![feature(test)]
910
#![deny(fuzzy_provenance_casts)]
1011

alloc/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@
147147
#![feature(slice_range)]
148148
#![feature(std_internals)]
149149
#![feature(str_internals)]
150-
#![feature(strict_provenance)]
151150
#![feature(trusted_fused)]
152151
#![feature(trusted_len)]
153152
#![feature(trusted_random_access)]
@@ -162,6 +161,8 @@
162161
//
163162
// Language features:
164163
// tidy-alphabetical-start
164+
#![cfg_attr(bootstrap, feature(strict_provenance))]
165+
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
165166
#![cfg_attr(not(test), feature(coroutine_trait))]
166167
#![cfg_attr(test, feature(panic_update_hook))]
167168
#![cfg_attr(test, feature(test))]

alloc/tests/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
#![feature(panic_update_hook)]
3333
#![feature(pointer_is_aligned_to)]
3434
#![feature(thin_box)]
35-
#![feature(strict_provenance)]
35+
#![cfg_attr(bootstrap, feature(strict_provenance))]
36+
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
3637
#![feature(drain_keep_rest)]
3738
#![feature(local_waker)]
3839
#![feature(vec_pop_if)]

core/src/intrinsics.rs

-1
Original file line numberDiff line numberDiff line change
@@ -2794,7 +2794,6 @@ where
27942794
/// #![feature(is_val_statically_known)]
27952795
/// #![feature(core_intrinsics)]
27962796
/// # #![allow(internal_features)]
2797-
/// #![feature(strict_provenance)]
27982797
/// use std::intrinsics::is_val_statically_known;
27992798
///
28002799
/// fn foo(x: &i32) -> bool {

core/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@
163163
#![feature(str_internals)]
164164
#![feature(str_split_inclusive_remainder)]
165165
#![feature(str_split_remainder)]
166-
#![feature(strict_provenance)]
167166
#![feature(ub_checks)]
168167
#![feature(unchecked_neg)]
169168
#![feature(unchecked_shifts)]
@@ -174,6 +173,8 @@
174173
//
175174
// Language features:
176175
// tidy-alphabetical-start
176+
#![cfg_attr(bootstrap, feature(strict_provenance))]
177+
#![cfg_attr(not(bootstrap), feature(strict_provenance_lints))]
177178
#![feature(abi_unadjusted)]
178179
#![feature(adt_const_params)]
179180
#![feature(allow_internal_unsafe)]

core/src/ptr/const_ptr.rs

+42-50
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,11 @@ impl<T: ?Sized> *const T {
137137

138138
/// Gets the "address" portion of the pointer.
139139
///
140-
/// This is similar to `self as usize`, which semantically discards *provenance* and
141-
/// *address-space* information. However, unlike `self as usize`, casting the returned address
142-
/// back to a pointer yields a [pointer without provenance][without_provenance], which is undefined behavior to dereference. To
143-
/// properly restore the lost information and obtain a dereferenceable pointer, use
140+
/// This is similar to `self as usize`, except that the [provenance][crate::ptr#provenance] of
141+
/// the pointer is discarded and not [exposed][crate::ptr#exposed-provenance]. This means that
142+
/// casting the returned address back to a pointer yields a [pointer without
143+
/// provenance][without_provenance], which is undefined behavior to dereference. To properly
144+
/// restore the lost information and obtain a dereferenceable pointer, use
144145
/// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
145146
///
146147
/// If using those APIs is not possible because there is no way to preserve a pointer with the
@@ -155,90 +156,81 @@ impl<T: ?Sized> *const T {
155156
/// perform a change of representation to produce a value containing only the address
156157
/// portion of the pointer. What that means is up to the platform to define.
157158
///
158-
/// This API and its claimed semantics are part of the Strict Provenance experiment, and as such
159-
/// might change in the future (including possibly weakening this so it becomes wholly
160-
/// equivalent to `self as usize`). See the [module documentation][crate::ptr] for details.
159+
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
161160
#[must_use]
162161
#[inline(always)]
163-
#[unstable(feature = "strict_provenance", issue = "95228")]
162+
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
164163
pub fn addr(self) -> usize {
165-
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
164+
// A pointer-to-integer transmute currently has exactly the right semantics: it returns the
165+
// address without exposing the provenance. Note that this is *not* a stable guarantee about
166+
// transmute semantics, it relies on sysroot crates having special status.
166167
// SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the
167168
// provenance).
168169
unsafe { mem::transmute(self.cast::<()>()) }
169170
}
170171

171-
/// Exposes the "provenance" part of the pointer for future use in
172-
/// [`with_exposed_provenance`][] and returns the "address" portion.
172+
/// Exposes the ["provenance"][crate::ptr#provenance] part of the pointer for future use in
173+
/// [`with_exposed_provenance`] and returns the "address" portion.
173174
///
174-
/// This is equivalent to `self as usize`, which semantically discards *provenance* and
175-
/// *address-space* information. Furthermore, this (like the `as` cast) has the implicit
176-
/// side-effect of marking the provenance as 'exposed', so on platforms that support it you can
177-
/// later call [`with_exposed_provenance`][] to reconstitute the original pointer including its
178-
/// provenance. (Reconstructing address space information, if required, is your responsibility.)
175+
/// This is equivalent to `self as usize`, which semantically discards provenance information.
176+
/// Furthermore, this (like the `as` cast) has the implicit side-effect of marking the
177+
/// provenance as 'exposed', so on platforms that support it you can later call
178+
/// [`with_exposed_provenance`] to reconstitute the original pointer including its provenance.
179179
///
180-
/// Using this method means that code is *not* following [Strict
181-
/// Provenance][super#strict-provenance] rules. Supporting
182-
/// [`with_exposed_provenance`][] complicates specification and reasoning and may not be supported by
183-
/// tools that help you to stay conformant with the Rust memory model, so it is recommended to
184-
/// use [`addr`][pointer::addr] wherever possible.
180+
/// Due to its inherent ambiguity, [`with_exposed_provenance`] may not be supported by tools
181+
/// that help you to stay conformant with the Rust memory model. It is recommended to use
182+
/// [Strict Provenance][crate::ptr#strict-provenance] APIs such as [`with_addr`][pointer::with_addr]
183+
/// wherever possible, in which case [`addr`][pointer::addr] should be used instead of `expose_provenance`.
185184
///
186185
/// On most platforms this will produce a value with the same bytes as the original pointer,
187186
/// because all the bytes are dedicated to describing the address. Platforms which need to store
188187
/// additional information in the pointer may not support this operation, since the 'expose'
189-
/// side-effect which is required for [`with_exposed_provenance`][] to work is typically not
188+
/// side-effect which is required for [`with_exposed_provenance`] to work is typically not
190189
/// available.
191190
///
192-
/// It is unclear whether this method can be given a satisfying unambiguous specification. This
193-
/// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
191+
/// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API.
194192
///
195193
/// [`with_exposed_provenance`]: with_exposed_provenance
196194
#[must_use]
197195
#[inline(always)]
198-
#[unstable(feature = "exposed_provenance", issue = "95228")]
196+
#[stable(feature = "exposed_provenance", since = "CURRENT_RUSTC_VERSION")]
199197
pub fn expose_provenance(self) -> usize {
200-
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
201198
self.cast::<()>() as usize
202199
}
203200

204-
/// Creates a new pointer with the given address.
201+
/// Creates a new pointer with the given address and the [provenance][crate::ptr#provenance] of
202+
/// `self`.
205203
///
206-
/// This performs the same operation as an `addr as ptr` cast, but copies
207-
/// the *address-space* and *provenance* of `self` to the new pointer.
208-
/// This allows us to dynamically preserve and propagate this important
209-
/// information in a way that is otherwise impossible with a unary cast.
204+
/// This is similar to a `addr as *const T` cast, but copies
205+
/// the *provenance* of `self` to the new pointer.
206+
/// This avoids the inherent ambiguity of the unary cast.
210207
///
211208
/// This is equivalent to using [`wrapping_offset`][pointer::wrapping_offset] to offset
212209
/// `self` to the given address, and therefore has all the same capabilities and restrictions.
213210
///
214-
/// This API and its claimed semantics are part of the Strict Provenance experiment,
215-
/// see the [module documentation][crate::ptr] for details.
211+
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
216212
#[must_use]
217213
#[inline]
218-
#[unstable(feature = "strict_provenance", issue = "95228")]
214+
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
219215
pub fn with_addr(self, addr: usize) -> Self {
220-
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
221-
//
222-
// In the mean-time, this operation is defined to be "as if" it was
223-
// a wrapping_offset, so we can emulate it as such. This should properly
224-
// restore pointer provenance even under today's compiler.
216+
// This should probably be an intrinsic to avoid doing any sort of arithmetic, but
217+
// meanwhile, we can implement it with `wrapping_offset`, which preserves the pointer's
218+
// provenance.
225219
let self_addr = self.addr() as isize;
226220
let dest_addr = addr as isize;
227221
let offset = dest_addr.wrapping_sub(self_addr);
228-
229-
// This is the canonical desugaring of this operation
230222
self.wrapping_byte_offset(offset)
231223
}
232224

233-
/// Creates a new pointer by mapping `self`'s address to a new one.
225+
/// Creates a new pointer by mapping `self`'s address to a new one, preserving the
226+
/// [provenance][crate::ptr#provenance] of `self`.
234227
///
235228
/// This is a convenience for [`with_addr`][pointer::with_addr], see that method for details.
236229
///
237-
/// This API and its claimed semantics are part of the Strict Provenance experiment,
238-
/// see the [module documentation][crate::ptr] for details.
230+
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
239231
#[must_use]
240232
#[inline]
241-
#[unstable(feature = "strict_provenance", issue = "95228")]
233+
#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")]
242234
pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self {
243235
self.with_addr(f(self.addr()))
244236
}
@@ -379,7 +371,7 @@ impl<T: ?Sized> *const T {
379371
/// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
380372
/// "wrapping around"), must fit in an `isize`.
381373
///
382-
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
374+
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
383375
/// [allocated object], and the entire memory range between `self` and the result must be in
384376
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
385377
/// of the address space.
@@ -560,7 +552,7 @@ impl<T: ?Sized> *const T {
560552
/// ## Examples
561553
///
562554
/// ```
563-
/// #![feature(ptr_mask, strict_provenance)]
555+
/// #![feature(ptr_mask)]
564556
/// let v = 17_u32;
565557
/// let ptr: *const u32 = &v;
566558
///
@@ -611,7 +603,7 @@ impl<T: ?Sized> *const T {
611603
/// * `self` and `origin` must either
612604
///
613605
/// * point to the same address, or
614-
/// * both be *derived from* a pointer to the same [allocated object], and the memory range between
606+
/// * both be [derived from][crate::ptr#provenance] a pointer to the same [allocated object], and the memory range between
615607
/// the two pointers must be in bounds of that object. (See below for an example.)
616608
///
617609
/// * The distance between the pointers, in bytes, must be an exact multiple
@@ -871,7 +863,7 @@ impl<T: ?Sized> *const T {
871863
/// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
872864
/// "wrapping around"), must fit in an `isize`.
873865
///
874-
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
866+
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
875867
/// [allocated object], and the entire memory range between `self` and the result must be in
876868
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
877869
/// of the address space.
@@ -978,7 +970,7 @@ impl<T: ?Sized> *const T {
978970
/// * The offset in bytes, `count * size_of::<T>()`, computed on mathematical integers (without
979971
/// "wrapping around"), must fit in an `isize`.
980972
///
981-
/// * If the computed offset is non-zero, then `self` must be derived from a pointer to some
973+
/// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some
982974
/// [allocated object], and the entire memory range between `self` and the result must be in
983975
/// bounds of that allocated object. In particular, this range must not "wrap around" the edge
984976
/// of the address space.

0 commit comments

Comments
 (0)