diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 3b45d46b31d5e..cda133d77890f 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -116,10 +116,11 @@ impl *const T { /// Gets the "address" portion of the pointer. /// - /// This is similar to `self as usize`, which semantically discards *provenance* and - /// *address-space* information. However, unlike `self as usize`, casting the returned address - /// back to a pointer yields a [pointer without provenance][without_provenance], which is undefined behavior to dereference. To - /// properly restore the lost information and obtain a dereferenceable pointer, use + /// This is similar to `self as usize`, except that the [provenance][crate::ptr#provenance] of + /// the pointer is discarded and not [exposed][crate::ptr#exposed-provenance]. This means that + /// casting the returned address back to a pointer yields a [pointer without + /// provenance][without_provenance], which is undefined behavior to dereference. To properly + /// restore the lost information and obtain a dereferenceable pointer, use /// [`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 @@ -134,67 +135,61 @@ impl *const T { /// perform a change of representation to produce a value containing only the address /// portion of the pointer. What that means is up to the platform to define. /// - /// This API and its claimed semantics are part of the Strict Provenance experiment, and as such - /// might change in the future (including possibly weakening this so it becomes wholly - /// equivalent to `self as usize`). See the [module documentation][crate::ptr] for details. + /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline(always)] - #[unstable(feature = "strict_provenance", issue = "95228")] + #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub fn addr(self) -> usize { - // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. + // A pointer-to-integer transmute has exactly the right semantics: it returns + // the address without exposing the provenance. // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the // provenance). unsafe { mem::transmute(self.cast::<()>()) } } - /// Exposes the "provenance" part of the pointer for future use in - /// [`with_exposed_provenance`][] and returns the "address" portion. + /// Exposes the ["provenance"][crate::ptr#provenance] part of the pointer for future use in + /// [`with_exposed_provenance`] and returns the "address" portion. /// - /// This is equivalent to `self as usize`, which semantically discards *provenance* and - /// *address-space* information. Furthermore, this (like the `as` cast) has the implicit - /// side-effect of marking the provenance as 'exposed', so on platforms that support it you can - /// later call [`with_exposed_provenance`][] to reconstitute the original pointer including its - /// provenance. (Reconstructing address space information, if required, is your responsibility.) + /// This is equivalent to `self as usize`, which semantically discards provenance information. + /// Furthermore, this (like the `as` cast) has the implicit side-effect of marking the + /// provenance as 'exposed', so on platforms that support it you can later call + /// [`with_exposed_provenance`] to reconstitute the original pointer including its provenance. /// - /// Using this method means that code is *not* following [Strict - /// Provenance][super#strict-provenance] rules. Supporting - /// [`with_exposed_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 [`addr`][pointer::addr] wherever possible. + /// Due to its inherent ambiguity, [`with_exposed_provenance`] may not be supported by tools + /// that help you to stay conformant with the Rust memory model. It is recommended to use + /// [Strict Provenance][crate::ptr#strict-provenance] APIs such as [`with_addr`][pointer::with_addr] + /// wherever possible, in which case [`addr`][pointer::addr] should be used instead of `expose_provenance`. /// /// 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. Platforms which need to store /// additional information in the pointer may not support this operation, since the 'expose' - /// side-effect which is required for [`with_exposed_provenance`][] to work is typically not + /// side-effect which is required for [`with_exposed_provenance`] to work is typically not /// available. /// - /// It is unclear whether this method can be given a satisfying unambiguous specification. This - /// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance]. + /// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. /// /// [`with_exposed_provenance`]: with_exposed_provenance #[must_use] #[inline(always)] - #[unstable(feature = "exposed_provenance", issue = "95228")] + #[stable(feature = "exposed_provenance", since = "CURRENT_RUSTC_VERSION")] pub fn expose_provenance(self) -> usize { - // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. self.cast::<()>() as usize } - /// Creates a new pointer with the given address. + /// Creates a new pointer with the given address and the [provenance][crate::ptr#provenance] of + /// `self`. /// - /// This performs the same operation as an `addr as ptr` cast, but copies - /// the *address-space* and *provenance* of `self` to the new pointer. - /// This allows us to dynamically preserve and propagate this important - /// information in a way that is otherwise impossible with a unary cast. + /// This is similar to a `addr as *const T` cast, but copies + /// the *provenance* of `self` to the new pointer. + /// This avoids the inherent ambiguity of the unary cast. /// /// 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, - /// see the [module documentation][crate::ptr] for details. + /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[unstable(feature = "strict_provenance", issue = "95228")] + #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub fn with_addr(self, addr: usize) -> Self { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // @@ -209,15 +204,15 @@ impl *const T { self.wrapping_byte_offset(offset) } - /// Creates a new pointer by mapping `self`'s address to a new one. + /// Creates a new pointer by mapping `self`'s address to a new one, preserving the + /// [provenance][crate::ptr#provenance] of `self`. /// /// This is a convenience for [`with_addr`][pointer::with_addr], see that method for details. /// - /// This API and its claimed semantics are part of the Strict Provenance experiment, - /// see the [module documentation][crate::ptr] for details. + /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[unstable(feature = "strict_provenance", issue = "95228")] + #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self { self.with_addr(f(self.addr())) } @@ -357,7 +352,7 @@ impl *const T { /// /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in /// bounds of that allocated object. In particular, this range must not "wrap around" the edge /// of the address space. @@ -561,7 +556,7 @@ impl *const T { /// * `self` and `origin` must either /// /// * point to the same address, or - /// * both be *derived from* a pointer to the same [allocated object], and the memory range between + /// * both be [derived from][crate::ptr#provenance] a pointer to the same [allocated object], and the memory range between /// the two pointers must be in bounds of that object. (See below for an example.) /// /// * The distance between the pointers, in bytes, must be an exact multiple @@ -818,7 +813,7 @@ impl *const T { /// /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in /// bounds of that allocated object. In particular, this range must not "wrap around" the edge /// of the address space. @@ -892,7 +887,7 @@ impl *const T { /// /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in /// bounds of that allocated object. In particular, this range must not "wrap around" the edge /// of the address space. diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 08d06cad55d06..c0bc0cbdb653d 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -130,65 +130,43 @@ //! //! [`null()`]: null //! -//! # Strict Provenance -//! -//! **The following text is non-normative, insufficiently formal, and is an extremely strict -//! interpretation of provenance. It's ok if your code doesn't strictly conform to it.** -//! -//! [Strict Provenance][] is an experimental set of APIs that help tools that try -//! to validate the memory-safety of your program's execution. Notably this includes [Miri][] -//! and [CHERI][], which can detect when you access out of bounds memory or otherwise violate -//! Rust's memory model. -//! -//! Provenance must exist in some form for any programming -//! language compiled for modern computer architectures, but specifying a model for provenance -//! in a way that is useful to both compilers and programmers is an ongoing challenge. -//! The [Strict Provenance][] experiment seeks to explore the question: *what if we just said you -//! couldn't do all the nasty operations that make provenance so messy?* -//! -//! What APIs would have to be removed? What APIs would have to be added? How much would code -//! have to change, and is it worse or better now? Would any patterns become truly inexpressible? -//! Could we carve out special exceptions for those patterns? Should we? -//! -//! A secondary goal of this project is to see if we can disambiguate the many functions of -//! pointer<->integer casts enough for the definition of `usize` to be loosened so that it -//! isn't *pointer*-sized but address-space/offset/allocation-sized (we'll probably continue -//! to conflate these notions). This would potentially make it possible to more efficiently -//! target platforms where pointers are larger than offsets, such as CHERI and maybe some -//! segmented architectures. -//! -//! ## Provenance -//! -//! **This section is *non-normative* and is part of the [Strict Provenance][] experiment.** +//! # Pointer Provenance //! //! Pointers are not *simply* an "integer" or "address". For instance, it's uncontroversial //! to say that a Use After Free is clearly Undefined Behaviour, even if you "get lucky" //! and the freed memory gets reallocated before your read/write (in fact this is the //! worst-case scenario, UAFs would be much less concerning if this didn't happen!). -//! To rationalize this claim, pointers need to somehow be *more* than just their addresses: -//! they must have provenance. +//! As another example, consider that [`wrapping_offset`] is documented to "remember" +//! the allocated object that the original pointer points to, even if it is offset far +//! outside the memory range occupied by that allocated object. +//! To rationalize claims like this, pointers need to somehow be *more* than just their addresses: +//! they must have **provenance**. //! //! When an allocation is created, that allocation has a unique Original Pointer. For alloc //! APIs this is literally the pointer the call returns, and for local variables and statics, -//! this is the name of the variable/static. This is mildly overloading the term "pointer" -//! for the sake of brevity/exposition. +//! this is the name of the variable/static. (This is mildly overloading the term "pointer" +//! for the sake of brevity/exposition.) //! //! The Original Pointer for an allocation is guaranteed to have unique access to the entire -//! allocation and *only* that allocation. In this sense, an allocation can be thought of -//! as a "sandbox" that cannot be broken into or out of. *Provenance* is the permission -//! to access an allocation's sandbox and has both a *spatial* and *temporal* component: +//! allocation and *only* that allocation. In this sense, an allocation can be thought of as a +//! "sandbox" that the pointer must not leave (at penalty of undefined behavior). *Provenance* is +//! about tracking each pointer's lineage back to the Original Pointer that it got derived from. +//! This controls which permission the pointer has to access an allocation's sandbox. This +//! permission has both a *spatial* and *temporal* component: //! //! * Spatial: A range of bytes that the pointer is allowed to access. -//! * Temporal: The lifetime (of the allocation) that access to these bytes is tied to. +//! * Temporal: The timespan during which the pointer is allowed to access these bytes. //! -//! Spatial provenance makes sure you don't go beyond your sandbox, while temporal provenance -//! makes sure that you can't "get lucky" after your permission to access some memory +//! Spatial provenance requires that you don't go beyond your sandbox, while temporal provenance +//! requires that you can't "get lucky" after your permission to access some memory //! has been revoked (either through deallocations or borrows expiring). //! //! Provenance is implicitly shared with all pointers transitively derived from -//! The Original Pointer through operations like [`offset`], borrowing, and pointer casts. +//! the Original Pointer through operations like [`offset`], borrowing, and pointer casts. //! Some operations may *shrink* the derived provenance, limiting how much memory it can -//! access or how long it's valid for (i.e. borrowing a subfield and subslicing). +//! access or how long it's valid for (i.e. borrowing a subfield and subslicing can shrink the +//! spatial component of provenance, and all borrowing can shrink the temporal component of +//! provenance). //! //! Shrinking provenance cannot be undone: even if you "know" there is a larger allocation, you //! can't derive a pointer with a larger provenance. Similarly, you cannot "recombine" @@ -200,53 +178,42 @@ //! If an allocation is deallocated, all pointers with provenance to that allocation become //! invalidated, and effectively lose their provenance. //! -//! The strict provenance experiment is mostly only interested in exploring stricter *spatial* -//! provenance. In this sense it can be thought of as a subset of the more ambitious and -//! formal [Stacked Borrows][] research project, which is what tools like [Miri][] are based on. -//! In particular, Stacked Borrows is necessary to properly describe what borrows are allowed -//! to do and when they become invalidated. This necessarily involves much more complex -//! *temporal* reasoning than simply identifying allocations. Adjusting APIs and code -//! for the strict provenance experiment will also greatly help Stacked Borrows. -//! +//! Note that the full definition of provenance in Rust is not decided yet, as this interacts +//! with the as-yet undecided [aliasing] rules. //! //! ## Pointer Vs Addresses //! -//! **This section is *non-normative* and is part of the [Strict Provenance][] experiment.** +//! A pointer value in Rust semantically contains the following information: //! -//! One of the largest historical issues with trying to define provenance is that programmers -//! freely convert between pointers and integers. Once you allow for this, it generally becomes -//! impossible to accurately track and preserve provenance information, and you need to appeal -//! to very complex and unreliable heuristics. But of course, converting between pointers and -//! integers is very useful, so what can we do? +//! * The **address** it points to, which can be represented by a `usize`. +//! * The **provenance** it has, defining the memory it has permission to access. Provenance can be +//! absent, in which case the pointer does not have permission to access any memory. //! -//! Also did you know WASM is actually a "Harvard Architecture"? As in function pointers are -//! handled completely differently from data pointers? And we kind of just shipped Rust on WASM -//! without really addressing the fact that we let you freely convert between function pointers -//! and data pointers, because it mostly Just Works? Let's just put that on the "pointer casts -//! are dubious" pile. +//! From this list, it becomes very clear that a `usize` *cannot* accurately represent a pointer, +//! and converting from a pointer to a `usize` is generally an operation which *only* extracts the +//! address. Converting this address back into pointer requires somehow answering the question: +//! which provenance should the resulting pointer have? //! -//! Strict Provenance attempts to square these circles by decoupling Rust's traditional conflation -//! of pointers and `usize` (and `isize`), and defining a pointer to semantically contain the -//! following information: +//! Rust provides two answers to this: *Strict Provenance* and *Exposed Provenance*. //! -//! * The **address-space** it is part of (e.g. "data" vs "code" in WASM). -//! * The **address** it points to, which can be represented by a `usize`. -//! * The **provenance** it has, defining the memory it has permission to access. -//! Provenance can be absent, in which case the pointer does not have permission to access any memory. +//! ## Strict Provenance +//! +//! "Strict Provenance" refers to a set of APIs designed to make working with provenance more +//! explicit. They are intended as substitutes for casting a pointer to an integer and back. //! -//! Under Strict Provenance, a `usize` *cannot* accurately represent a pointer, and converting from -//! a pointer to a `usize` is generally an operation which *only* extracts the address. It is -//! therefore *impossible* to construct a valid pointer from a `usize` because there is no way -//! to restore the address-space and provenance. In other words, pointer-integer-pointer -//! roundtrips are not possible (in the sense that the resulting pointer is not dereferenceable). +//! Entirely avoiding integer-to-pointer casts successfully side-steps the inherent ambiguity of +//! that operation. This benefits compiler optimizations, and it is pretty much a requirement for +//! using tools like [Miri] and architectures like [CHERI] that aim to detect and diagnose pointer +//! misuse. //! -//! The key insight to making this model *at all* viable is the [`with_addr`][] method: +//! The key insight to making programming without integer-to-pointer casts *at all* viable is the +//! [`with_addr`] method: //! //! ```text //! /// Creates a new pointer with the given address. //! /// //! /// This performs the same operation as an `addr as ptr` cast, but copies -//! /// the *address-space* and *provenance* of `self` to the new pointer. +//! /// the *provenance* of `self` to the new pointer. //! /// This allows us to dynamically preserve and propagate this important //! /// information in a way that is otherwise impossible with a unary cast. //! /// @@ -257,23 +224,21 @@ //! //! So you're still able to drop down to the address representation and do whatever //! clever bit tricks you want *as long as* you're able to keep around a pointer -//! into the allocation you care about that can "reconstitute" the other parts of the pointer. +//! into the allocation you care about that can "reconstitute" the provenance. //! Usually this is very easy, because you only are taking a pointer, messing with the address, //! and then immediately converting back to a pointer. To make this use case more ergonomic, -//! we provide the [`map_addr`][] method. +//! we provide the [`map_addr`] method. //! //! To help make it clear that code is "following" Strict Provenance semantics, we also provide an -//! [`addr`][] method which promises that the returned address is not part of a -//! pointer-usize-pointer roundtrip. In the future we may provide a lint for pointer<->integer +//! [`addr`] method which promises that the returned address is not part of a +//! pointer-integer-pointer roundtrip. In the future we may provide a lint for pointer<->integer //! casts to help you audit if your code conforms to strict provenance. //! -//! -//! ## Using Strict Provenance +//! ### Using Strict Provenance //! //! Most code needs no changes to conform to strict provenance, as the only really concerning -//! operation that *wasn't* obviously already Undefined Behaviour is casts from usize to a -//! pointer. For code which *does* cast a `usize` to a pointer, the scope of the change depends -//! on exactly what you're doing. +//! operation is casts from usize to a pointer. For code which *does* cast a `usize` to a pointer, +//! the scope of the change depends on exactly what you're doing. //! //! In general, you just need to make sure that if you want to convert a `usize` address to a //! pointer and then use that pointer to read/write memory, you need to keep around a pointer @@ -314,16 +279,9 @@ //! be using AtomicPtr instead. If that messes up the way you atomically manipulate pointers, //! we would like to know why, and what needs to be done to fix it.) //! -//! Something more complicated and just generally *evil* like an XOR-List requires more significant -//! changes like allocating all nodes in a pre-allocated Vec or Arena and using a pointer -//! to the whole allocation to reconstitute the XORed addresses. -//! //! Situations where a valid pointer *must* be created from just an address, such as baremetal code -//! accessing a memory-mapped interface at a fixed address, are an open question on how to support. -//! These situations *will* still be allowed, but we might require some kind of "I know what I'm -//! doing" annotation to explain the situation to the compiler. It's also possible they need no -//! special attention at all, because they're generally accessing memory outside the scope of -//! "the abstract machine", or already using "I know what I'm doing" annotations like "volatile". +//! accessing a memory-mapped interface at a fixed address, cannot currently be handled with strict +//! provenance APIs and should use [exposed provenance](#exposed-provenance). //! //! Under [Strict Provenance] it is Undefined Behaviour to: //! @@ -336,7 +294,7 @@ //! //! But it *is* still sound to: //! -//! * Create a pointer without provenance from just an address (see [`ptr::dangling`][]). Such a +//! * Create a pointer without provenance from just an address (see [`ptr::dangling`]). Such a //! pointer cannot be used for memory accesses (except for zero-sized accesses). This can still be //! useful for sentinel values like `null` *or* to represent a tagged pointer that will never be //! dereferenceable. In general, it is always sound for an integer to pretend to be a pointer "for @@ -344,16 +302,12 @@ //! offset, read, write, etc). //! //! * Forge an allocation of size zero at any sufficiently aligned non-null address. -//! i.e. the usual "ZSTs are fake, do what you want" rules apply *but* this only applies -//! for actual forgery (integers cast to pointers). If you borrow some struct's field -//! that *happens* to be zero-sized, the resulting pointer will have provenance tied to -//! that allocation, and it will still get invalidated if the allocation gets deallocated. -//! In the future we may introduce an API to make such a forged allocation explicit. +//! i.e. the usual "ZSTs are fake, do what you want" rules apply. //! -//! * [`wrapping_offset`][] a pointer outside its provenance. This includes pointers +//! * [`wrapping_offset`] a pointer outside its provenance. This includes pointers //! which have "no" provenance. Unfortunately there may be practical limits on this for a //! particular platform, and it's an open question as to how to specify this (if at all). -//! Notably, [CHERI][] relies on a compression scheme that can't handle a +//! Notably, [CHERI] relies on a compression scheme that can't handle a //! pointer getting offset "too far" out of bounds. If this happens, the address //! returned by `addr` will be the value you expect, but the provenance will get invalidated //! and using it to read/write will fault. The details of this are architecture-specific @@ -371,7 +325,7 @@ //! the other's allocation (bytes), because they still have different provenance. //! //! * Perform pointer tagging tricks. This falls out of [`wrapping_offset`] but is worth -//! mentioning in more detail because of the limitations of [CHERI][]. Low-bit tagging +//! mentioning in more detail because of the limitations of [CHERI]. Low-bit tagging //! is very robust, and often doesn't even go out of bounds because types ensure //! size >= align (and over-aligning actually gives CHERI more flexibility). Anything //! more complex than this rapidly enters "extremely platform-specific" territory as @@ -381,48 +335,49 @@ //! //! ## Exposed Provenance //! -//! **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]. +//! As discussed above, integer-to-pointer casts are not possible with Strict Provenance APIs. //! 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. +//! confident can be formalized unambiguously and can be subject to precise formal reasoning. +//! Integer-to-pointer casts do not (currently) have such a clear specification. //! -//! However, there exist situations where pointer-usize-pointer roundtrips cannot be avoided, or +//! However, there exist situations where integer-to-pointer casts 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]. +//! that `usize` can capture all the information that makes up a pointer. +//! Bare-metal platforms can also require the synthesis of a pointer "out of thin air" without +//! anywhere to obtain proper provenance from. +//! +//! Rust's model for dealing with integer-to-pointer casts is called *Exposed Provenance*. However, +//! the semantics of Exposed Provenance are on much less solid footing than Strict Provenance, and +//! at this point it is not yet clear whether a satisfying unambiguous semantics can be defined for +//! Exposed Provenance. (If that sounds bad, be reassured that other popular languages that provide +//! integer-to-pointer casts are not faring any better.) Furthermore, Exposed Provenance will not +//! work (well) with tools like [Miri] and [CHERI]. //! //! Exposed Provenance is provided by the [`expose_provenance`] and [`with_exposed_provenance`] methods, -//! which are meant to replace `as` casts between pointers and integers. [`expose_provenance`] 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].) [`with_exposed_provenance`] -//! can be used to construct a pointer with one of these previously 'exposed' provenances. -//! [`with_exposed_provenance`] takes only `addr: usize` as arguments, so unlike in [`with_addr`] there is -//! no indication of what the correct provenance for the returned pointer is -- and that is exactly -//! what makes pointer-usize-pointer roundtrips so tricky to rigorously specify! 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. However, if -//! there is *no* previously 'exposed' provenance that justifies the way the returned pointer will -//! be used, the program has undefined behavior. -//! -//! Using [`expose_provenance`] or [`with_exposed_provenance`] (or the `as` casts) means that code is -//! *not* following Strict Provenance rules. The goal of the Strict Provenance experiment is to -//! determine how far one can get in Rust without the use of [`expose_provenance`] and -//! [`with_exposed_provenance`], 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. +//! which are equivalent to `as` casts between pointers and integers. +//! - [`expose_provenance`] 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].) +//! 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. +//! - [`with_exposed_provenance`] can be used to construct a pointer with one of these previously +//! 'exposed' provenances. [`with_exposed_provenance`] takes only `addr: usize` as arguments, so +//! unlike in [`with_addr`] there is no indication of what the correct provenance for the returned +//! pointer is -- and that is exactly what makes integer-to-pointer casts so tricky to rigorously +//! specify! The compiler will do its best to pick the right provenance for you, but currently we +//! cannot provide any guarantees about which provenance the resulting pointer will have. Only one +//! thing is clear: if there is *no* previously 'exposed' provenance that justifies the way the +//! returned pointer will be used, the program has undefined behavior. +//! +//! If at all possible, we encourage code to be ported to [Strict Provenance] APIs, thus avoiding +//! the need for Exposed Provenance. 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. However, we acknowledge that this +//! is not always possible, and offer Exposed Provenance as a way to explicit "opt out" of the +//! well-defined semantics of Strict Provenance, and "opt in" to the unclear semantics of +//! integer-to-pointer casts. //! //! [aliasing]: ../../nomicon/aliasing.html //! [book]: ../../book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer @@ -439,8 +394,7 @@ //! [`with_exposed_provenance`]: with_exposed_provenance //! [Miri]: https://github.com/rust-lang/miri //! [CHERI]: https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/ -//! [Strict Provenance]: https://github.com/rust-lang/rust/issues/95228 -//! [Stacked Borrows]: https://plv.mpi-sws.org/rustbelt/stacked-borrows/ +//! [Strict Provenance]: #strict-provenance #![stable(feature = "rust1", since = "1.0.0")] // There are many unsafe functions taking pointers that don't dereference them. @@ -631,7 +585,7 @@ pub const fn null_mut() -> *mut T { from_raw_parts_mut(without_provenance_mut::<()>(0), ()) } -/// Creates a pointer with the given address and no provenance. +/// Creates a pointer with the given address and no [provenance][crate::ptr#provenance]. /// /// This is equivalent to `ptr::null().with_addr(addr)`. /// @@ -643,16 +597,14 @@ pub const fn null_mut() -> *mut T { /// This is different from `addr as *const T`, which creates a pointer that picks up a previously /// exposed provenance. See [`with_exposed_provenance`] for more details on that operation. /// -/// This API and its claimed semantics are part of the Strict Provenance experiment, -/// see the [module documentation][crate::ptr] for details. +/// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[inline(always)] #[must_use] #[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] -#[unstable(feature = "strict_provenance", issue = "95228")] +#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub const fn without_provenance(addr: usize) -> *const T { - // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. - // We use transmute rather than a cast so tools like Miri can tell that this - // is *not* the same as with_exposed_provenance. + // An int-to-pointer transmute has exactly the intended semantics: it creates a pointer without + // provenance. // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that // pointer). unsafe { mem::transmute(addr) } @@ -670,12 +622,12 @@ pub const fn without_provenance(addr: usize) -> *const T { #[inline(always)] #[must_use] #[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] -#[unstable(feature = "strict_provenance", issue = "95228")] +#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub const fn dangling() -> *const T { without_provenance(mem::align_of::()) } -/// Creates a pointer with the given address and no provenance. +/// Creates a pointer with the given address and no [provenance][crate::ptr#provenance]. /// /// This is equivalent to `ptr::null_mut().with_addr(addr)`. /// @@ -687,16 +639,14 @@ pub const fn dangling() -> *const T { /// This is different from `addr as *mut T`, which creates a pointer that picks up a previously /// exposed provenance. See [`with_exposed_provenance_mut`] for more details on that operation. /// -/// This API and its claimed semantics are part of the Strict Provenance experiment, -/// see the [module documentation][crate::ptr] for details. +/// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[inline(always)] #[must_use] #[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] -#[unstable(feature = "strict_provenance", issue = "95228")] +#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub const fn without_provenance_mut(addr: usize) -> *mut T { - // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. - // We use transmute rather than a cast so tools like Miri can tell that this - // is *not* the same as with_exposed_provenance. + // An int-to-pointer transmute has exactly the intended semantics: it creates a pointer without + // provenance. // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that // pointer). unsafe { mem::transmute(addr) } @@ -714,96 +664,86 @@ pub const fn without_provenance_mut(addr: usize) -> *mut T { #[inline(always)] #[must_use] #[rustc_const_stable(feature = "stable_things_using_strict_provenance", since = "1.61.0")] -#[unstable(feature = "strict_provenance", issue = "95228")] +#[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub const fn dangling_mut() -> *mut T { without_provenance_mut(mem::align_of::()) } -/// Converts an address back to a pointer, picking up a previously 'exposed' provenance. +/// Converts an address back to a pointer, picking up some previously 'exposed' +/// [provenance][crate::ptr#provenance]. /// -/// 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_provenance`][pointer::expose_provenance], 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 fully equivalent to `addr as *const T`. The provenance of the returned pointer is that +/// of *some* pointer that was previously exposed by passing it to +/// [`expose_provenance`][pointer::expose_provenance], 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 -/// and references that have been invalidated due to aliasing accesses cannot be used anymore, -/// even if they have been exposed! +/// The exact provenance that gets picked is not specified. The compiler will do its best to pick +/// the "right" provenance for you (whatever that may be), but currently we cannot provide any +/// guarantees about which provenance the resulting pointer will have. /// -/// 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 (while upholding all aliasing requirements), -/// then that is the guess that will be taken. +/// If there is *no* previously 'exposed' provenance that justifies the way the returned pointer +/// will be used, the program has undefined behavior. In particular, the aliasing rules still apply: +/// pointers and references that have been invalidated due to aliasing accesses cannot be used +/// anymore, even if they have been exposed! /// -/// 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 function means that code is *not* following [Strict -/// Provenance][self#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. +/// Due to its inherent ambiguity, this operation may not be supported by tools that help you to +/// stay conformant with the Rust memory model. It is recommended to use [Strict +/// Provenance][self#strict-provenance] APIs such as [`with_addr`][pointer::with_addr] wherever +/// possible. /// /// On most platforms this will produce a value with the same bytes as the address. Platforms /// which need to store additional information in a pointer may not support this operation, /// since it is generally not possible to actually *compute* which provenance the returned /// pointer has to pick up. /// -/// It is unclear whether this function can be given a satisfying unambiguous specification. This -/// API and its claimed semantics are part of [Exposed Provenance][self#exposed-provenance]. +/// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. #[must_use] #[inline(always)] -#[unstable(feature = "exposed_provenance", issue = "95228")] +#[stable(feature = "exposed_provenance", since = "CURRENT_RUSTC_VERSION")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead -pub fn with_exposed_provenance(addr: usize) -> *const T -where - T: Sized, -{ - // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. +pub fn with_exposed_provenance(addr: usize) -> *const T { addr as *const T } -/// Converts an address back to a mutable pointer, picking up a previously 'exposed' provenance. +/// Converts an address back to a mutable pointer, picking up some previously 'exposed' +/// [provenance][crate::ptr#provenance]. +/// +/// This is fully equivalent to `addr as *mut T`. The provenance of the returned pointer is that +/// of *some* pointer that was previously exposed by passing it to +/// [`expose_provenance`][pointer::expose_provenance], 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 *mut T`. The provenance of the -/// returned pointer is that of *any* pointer that was previously passed to -/// [`expose_provenance`][pointer::expose_provenance] 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. +/// The exact provenance that gets picked is not specified. The compiler will do its best to pick +/// the "right" provenance for you (whatever that may be), but currently we cannot provide any +/// guarantees about which provenance the resulting pointer will have. /// -/// 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. +/// If there is *no* previously 'exposed' provenance that justifies the way the returned pointer +/// will be used, the program has undefined behavior. In particular, the aliasing rules still apply: +/// pointers and references that have been invalidated due to aliasing accesses cannot be used +/// anymore, even if they have been exposed! /// -/// Using this function means that code is *not* following [Strict -/// Provenance][self#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. +/// Due to its inherent ambiguity, this operation may not be supported by tools that help you to +/// stay conformant with the Rust memory model. It is recommended to use [Strict +/// Provenance][self#strict-provenance] APIs such as [`with_addr`][pointer::with_addr] wherever +/// possible. /// /// On most platforms this will produce a value with the same bytes as the address. Platforms /// which need to store additional information in a pointer may not support this operation, /// since it is generally not possible to actually *compute* which provenance the returned /// pointer has to pick up. /// -/// It is unclear whether this function can be given a satisfying unambiguous specification. This -/// API and its claimed semantics are part of [Exposed Provenance][self#exposed-provenance]. +/// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. #[must_use] #[inline(always)] -#[unstable(feature = "exposed_provenance", issue = "95228")] +#[stable(feature = "exposed_provenance", since = "CURRENT_RUSTC_VERSION")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[allow(fuzzy_provenance_casts)] // this *is* the explicit provenance API one should use instead -pub fn with_exposed_provenance_mut(addr: usize) -> *mut T -where - T: Sized, -{ - // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. +pub fn with_exposed_provenance_mut(addr: usize) -> *mut T { addr as *mut T } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index ddb9195d2e7c7..648f9138d2dff 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -104,12 +104,12 @@ impl *mut T { /// Gets the "address" portion of the pointer. /// - /// This is similar to `self as usize`, which semantically discards *provenance* and - /// *address-space* information. However, unlike `self as usize`, casting the returned address - /// back to a pointer yields a [pointer without provenance][without_provenance_mut], which is undefined - /// behavior to dereference. To properly restore the lost information and obtain a - /// dereferenceable pointer, use [`with_addr`][pointer::with_addr] or - /// [`map_addr`][pointer::map_addr]. + /// This is similar to `self as usize`, except that the [provenance][crate::ptr#provenance] of + /// the pointer is discarded and not [exposed][crate::ptr#exposed-provenance]. This means that + /// casting the returned address back to a pointer yields a [pointer without + /// provenance][without_provenance_mut], which is undefined behavior to dereference. To properly + /// restore the lost information and obtain a dereferenceable pointer, use + /// [`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, then Strict Provenance might not be for you. Use pointer-integer casts @@ -123,66 +123,60 @@ impl *mut T { /// perform a change of representation to produce a value containing only the address /// portion of the pointer. What that means is up to the platform to define. /// - /// This API and its claimed semantics are part of the Strict Provenance experiment, and as such - /// might change in the future (including possibly weakening this so it becomes wholly - /// equivalent to `self as usize`). See the [module documentation][crate::ptr] for details. + /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline(always)] - #[unstable(feature = "strict_provenance", issue = "95228")] + #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub fn addr(self) -> usize { - // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. + // A pointer-to-integer transmute has exactly the right semantics: it returns + // the address without exposing the provenance. // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the // provenance). unsafe { mem::transmute(self.cast::<()>()) } } - /// Exposes the "provenance" part of the pointer for future use in - /// [`with_exposed_provenance`][] and returns the "address" portion. + /// Exposes the ["provenance"][crate::ptr#provenance] part of the pointer for future use in + /// [`with_exposed_provenance_mut`] and returns the "address" portion. /// - /// This is equivalent to `self as usize`, which semantically discards *provenance* and - /// *address-space* information. Furthermore, this (like the `as` cast) has the implicit - /// side-effect of marking the provenance as 'exposed', so on platforms that support it you can - /// later call [`with_exposed_provenance_mut`][] to reconstitute the original pointer including its - /// provenance. (Reconstructing address space information, if required, is your responsibility.) + /// This is equivalent to `self as usize`, which semantically discards provenance information. + /// Furthermore, this (like the `as` cast) has the implicit side-effect of marking the + /// provenance as 'exposed', so on platforms that support it you can later call + /// [`with_exposed_provenance_mut`] to reconstitute the original pointer including its provenance. /// - /// Using this method means that code is *not* following [Strict - /// Provenance][super#strict-provenance] rules. Supporting - /// [`with_exposed_provenance_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. + /// Due to its inherent ambiguity, [`with_exposed_provenance_mut`] may not be supported by tools + /// that help you to stay conformant with the Rust memory model. It is recommended to use + /// [Strict Provenance][crate::ptr#strict-provenance] APIs such as [`with_addr`][pointer::with_addr] + /// wherever possible, in which case [`addr`][pointer::addr] should be used instead of `expose_provenance`. /// /// 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. Platforms which need to store /// additional information in the pointer may not support this operation, since the 'expose' - /// side-effect which is required for [`with_exposed_provenance_mut`][] to work is typically not + /// side-effect which is required for [`with_exposed_provenance_mut`] to work is typically not /// available. /// - /// It is unclear whether this method can be given a satisfying unambiguous specification. This - /// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance]. + /// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. /// /// [`with_exposed_provenance_mut`]: with_exposed_provenance_mut #[inline(always)] - #[unstable(feature = "exposed_provenance", issue = "95228")] + #[stable(feature = "exposed_provenance", since = "CURRENT_RUSTC_VERSION")] pub fn expose_provenance(self) -> usize { - // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. self.cast::<()>() as usize } - /// Creates a new pointer with the given address. + /// Creates a new pointer with the given address and the [provenance][crate::ptr#provenance] of + /// `self`. /// - /// This performs the same operation as an `addr as ptr` cast, but copies - /// the *address-space* and *provenance* of `self` to the new pointer. - /// This allows us to dynamically preserve and propagate this important - /// information in a way that is otherwise impossible with a unary cast. + /// This is similar to a `addr as *mut T` cast, but copies + /// the *provenance* of `self` to the new pointer. + /// This avoids the inherent ambiguity of the unary cast. /// /// 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 an extension to the Strict Provenance experiment, - /// see the [module documentation][crate::ptr] for details. + /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[unstable(feature = "strict_provenance", issue = "95228")] + #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub fn with_addr(self, addr: usize) -> Self { // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. // @@ -197,15 +191,15 @@ impl *mut T { self.wrapping_byte_offset(offset) } - /// Creates a new pointer by mapping `self`'s address to a new one. + /// Creates a new pointer by mapping `self`'s address to a new one, preserving the original + /// pointer's [provenance][crate::ptr#provenance]. /// /// This is a convenience for [`with_addr`][pointer::with_addr], see that method for details. /// - /// This API and its claimed semantics are part of the Strict Provenance experiment, - /// see the [module documentation][crate::ptr] for details. + /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[unstable(feature = "strict_provenance", issue = "95228")] + #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self { self.with_addr(f(self.addr())) } @@ -355,7 +349,7 @@ impl *mut T { /// /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in /// bounds of that allocated object. In particular, this range must not "wrap around" the edge /// of the address space. @@ -726,7 +720,7 @@ impl *mut T { /// * `self` and `origin` must either /// /// * point to the same address, or - /// * both be *derived from* a pointer to the same [allocated object], and the memory range between + /// * both be [derived from][crate::ptr#provenance] a pointer to the same [allocated object], and the memory range between /// the two pointers must be in bounds of that object. (See below for an example.) /// /// * The distance between the pointers, in bytes, must be an exact multiple @@ -899,7 +893,7 @@ impl *mut T { /// /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in /// bounds of that allocated object. In particular, this range must not "wrap around" the edge /// of the address space. @@ -973,7 +967,7 @@ impl *mut T { /// /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. /// - /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some + /// * If the computed offset is non-zero, then `self` must be [derived from][crate::ptr#provenance] a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in /// bounds of that allocated object. In particular, this range must not "wrap around" the edge /// of the address space. diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 673acc2972fe4..d438b67672555 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -265,40 +265,39 @@ impl NonNull { /// /// For more details see the equivalent method on a raw pointer, [`pointer::addr`]. /// - /// This API and its claimed semantics are part of the Strict Provenance experiment, - /// see the [`ptr` module documentation][crate::ptr]. + /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[unstable(feature = "strict_provenance", issue = "95228")] + #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub fn addr(self) -> NonZero { // SAFETY: The pointer is guaranteed by the type to be non-null, // meaning that the address will be non-zero. unsafe { NonZero::new_unchecked(self.pointer.addr()) } } - /// Creates a new pointer with the given address. + /// Creates a new pointer with the given address and the [provenance][crate::ptr#provenance] of + /// `self`. /// /// For more details see the equivalent method on a raw pointer, [`pointer::with_addr`]. /// - /// This API and its claimed semantics are part of the Strict Provenance experiment, - /// see the [`ptr` module documentation][crate::ptr]. + /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[unstable(feature = "strict_provenance", issue = "95228")] + #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub fn with_addr(self, addr: NonZero) -> Self { // SAFETY: The result of `ptr::from::with_addr` is non-null because `addr` is guaranteed to be non-zero. unsafe { NonNull::new_unchecked(self.pointer.with_addr(addr.get()) as *mut _) } } - /// Creates a new pointer by mapping `self`'s address to a new one. + /// Creates a new pointer by mapping `self`'s address to a new one, preserving the + /// [provenance][crate::ptr#provenance] of `self`. /// /// For more details see the equivalent method on a raw pointer, [`pointer::map_addr`]. /// - /// This API and its claimed semantics are part of the Strict Provenance experiment, - /// see the [`ptr` module documentation][crate::ptr]. + /// This is a [Strict Provenance][crate::ptr#strict-provenance] API. #[must_use] #[inline] - #[unstable(feature = "strict_provenance", issue = "95228")] + #[stable(feature = "strict_provenance", since = "CURRENT_RUSTC_VERSION")] pub fn map_addr(self, f: impl FnOnce(NonZero) -> NonZero) -> Self { self.with_addr(f(self.addr())) }