44//!
55//! # Safety
66//!
7- //! Many functions in this module take raw pointers as arguments and read from
8- //! or write to them. For this to be safe, these pointers must be *valid*.
9- //! Whether a pointer is valid depends on the operation it is used for
10- //! (read or write), and the extent of the memory that is accessed (i.e.,
11- //! how many bytes are read/written) . Most functions use `*mut T` and `*const T`
12- //! to access only a single value, in which case the documentation omits the size
13- //! and implicitly assumes it to be `size_of::<T>()` bytes.
7+ //! Many functions in this module take raw pointers as arguments and read from or write to them. For
8+ //! this to be safe, these pointers must be *valid* for the given access. Whether a pointer is valid
9+ //! depends on the operation it is used for (read or write), and the extent of the memory that is
10+ //! accessed (i.e., how many bytes are read/written) -- it makes no sense to ask " is this pointer
11+ //! valid"; one has to ask "is this pointer valid for a given access" . Most functions use `*mut T`
12+ //! and `*const T` to access only a single value, in which case the documentation omits the size and
13+ //! implicitly assumes it to be `size_of::<T>()` bytes.
1414//!
1515//! The precise rules for validity are not determined yet. The guarantees that are
1616//! provided at this point are very minimal:
2626//! some memory happens to exist at that address and gets deallocated. This corresponds to writing
2727//! your own allocator: allocating zero-sized objects is not very hard. The canonical way to
2828//! obtain a pointer that is valid for zero-sized accesses is [`NonNull::dangling`].
29- //FIXME: mention `ptr::invalid ` above, once it is stable.
29+ //FIXME: mention `ptr::dangling ` above, once it is stable.
3030//! * All accesses performed by functions in this module are *non-atomic* in the sense
3131//! of [atomic operations] used to synchronize between threads. This means it is
3232//! undefined behavior to perform two concurrent accesses to the same location from different
4444//! information, see the [book] as well as the section in the reference devoted
4545//! to [undefined behavior][ub].
4646//!
47+ //! We say that a pointer is "dangling" if it is not valid for any non-zero-sized accesses. This
48+ //! means out-of-bounds pointers, pointers to freed memory, null pointers, and pointers created with
49+ //! [`NonNull::dangling`] are all dangling.
50+ //!
4751//! ## Alignment
4852//!
4953//! Valid raw pointers as defined above are not necessarily properly aligned (where
167171//! * The **address-space** it is part of (e.g. "data" vs "code" in WASM).
168172//! * The **address** it points to, which can be represented by a `usize`.
169173//! * The **provenance** it has, defining the memory it has permission to access.
174+ //! Provenance can be absent, in which case the pointer does not have permission to access any memory.
170175//!
171176//! Under Strict Provenance, a usize *cannot* accurately represent a pointer, and converting from
172177//! a pointer to a usize is generally an operation which *only* extracts the address. It is
270275//!
271276//! But it *is* still sound to:
272277//!
273- //! * Create an invalid pointer from just an address (see [`ptr::invalid`][]). This can
274- //! be used for sentinel values like `null` *or* to represent a tagged pointer that will
275- //! never be dereferenceable. In general, it is always sound for an integer to pretend
276- //! to be a pointer "for fun" as long as you don't use operations on it which require
277- //! it to be valid (offset, read, write, etc).
278+ //! * Create a pointer without provenance from just an address (see [`ptr::dangling`][]). Such a
279+ //! pointer cannot be used for memory accesses (except for zero-sized accesses). This can still be
280+ //! useful for sentinel values like `null` *or* to represent a tagged pointer that will never be
281+ //! dereferenceable. In general, it is always sound for an integer to pretend to be a pointer "for
282+ //! fun" as long as you don't use operations on it which require it to be valid (non-zero-sized
283+ //! offset, read, write, etc).
278284//!
279285//! * Forge an allocation of size zero at any sufficiently aligned non-null address.
280286//! i.e. the usual "ZSTs are fake, do what you want" rules apply *but* this only applies
283289//! that allocation and it will still get invalidated if the allocation gets deallocated.
284290//! In the future we may introduce an API to make such a forged allocation explicit.
285291//!
286- //! * [`wrapping_offset`][] a pointer outside its provenance. This includes invalid pointers
292+ //! * [`wrapping_offset`][] a pointer outside its provenance. This includes pointers
287293//! which have "no" provenance. Unfortunately there may be practical limits on this for a
288294//! particular platform, and it's an open question as to how to specify this (if at all).
289295//! Notably, [CHERI][] relies on a compression scheme that can't handle a
294300//! generous (think kilobytes, not bytes).
295301//!
296302//! * Compare arbitrary pointers by address. Addresses *are* just integers and so there is
297- //! always a coherent answer, even if the pointers are invalid or from different
303+ //! always a coherent answer, even if the pointers are dangling or from different
298304//! address-spaces/provenances. Of course, comparing addresses from different address-spaces
299305//! is generally going to be *meaningless*, but so is comparing Kilograms to Meters, and Rust
300306//! doesn't prevent that either. Similarly, if you get "lucky" and notice that a pointer
367373//! [`with_addr`]: pointer::with_addr
368374//! [`map_addr`]: pointer::map_addr
369375//! [`addr`]: pointer::addr
370- //! [`ptr::invalid `]: core::ptr::invalid
376+ //! [`ptr::dangling `]: core::ptr::dangling
371377//! [`expose_addr`]: pointer::expose_addr
372378//! [`from_exposed_addr`]: from_exposed_addr
373379//! [Miri]: https://github.com/rust-lang/miri
@@ -537,7 +543,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
537543#[ rustc_allow_const_fn_unstable( ptr_metadata) ]
538544#[ rustc_diagnostic_item = "ptr_null" ]
539545pub const fn null < T : ?Sized + Thin > ( ) -> * const T {
540- from_raw_parts ( invalid ( 0 ) , ( ) )
546+ from_raw_parts ( without_provenance ( 0 ) , ( ) )
541547}
542548
543549/// Creates a null mutable raw pointer.
@@ -563,32 +569,26 @@ pub const fn null<T: ?Sized + Thin>() -> *const T {
563569#[ rustc_allow_const_fn_unstable( ptr_metadata) ]
564570#[ rustc_diagnostic_item = "ptr_null_mut" ]
565571pub const fn null_mut < T : ?Sized + Thin > ( ) -> * mut T {
566- from_raw_parts_mut ( invalid_mut ( 0 ) , ( ) )
572+ from_raw_parts_mut ( without_provenance_mut ( 0 ) , ( ) )
567573}
568574
569- /// Creates an invalid pointer with the given address.
575+ /// Creates a pointer with the given address and no provenance.
576+ ///
577+ /// Without provenance, this pointer is not associated with any actual allocation. Such a
578+ /// no-provenance pointer may be used for zero-sized memory accesses (if suitably aligned), but
579+ /// non-zero-sized memory accesses with a no-provenance pointer are UB. No-provenance pointers are
580+ /// little more than a usize address in disguise.
570581///
571582/// This is different from `addr as *const T`, which creates a pointer that picks up a previously
572583/// exposed provenance. See [`from_exposed_addr`] for more details on that operation.
573584///
574- /// The module's top-level documentation discusses the precise meaning of an "invalid"
575- /// pointer but essentially this expresses that the pointer is not associated
576- /// with any actual allocation and is little more than a usize address in disguise.
577- ///
578- /// This pointer will have no provenance associated with it and is therefore
579- /// UB to read/write/offset. This mostly exists to facilitate things
580- /// like `ptr::null` and `NonNull::dangling` which make invalid pointers.
581- ///
582- /// (Standard "Zero-Sized-Types get to cheat and lie" caveats apply, although it
583- /// may be desirable to give them their own API just to make that 100% clear.)
584- ///
585585/// This API and its claimed semantics are part of the Strict Provenance experiment,
586586/// see the [module documentation][crate::ptr] for details.
587587#[ inline( always) ]
588588#[ must_use]
589589#[ rustc_const_stable( feature = "stable_things_using_strict_provenance" , since = "1.61.0" ) ]
590590#[ unstable( feature = "strict_provenance" , issue = "95228" ) ]
591- pub const fn invalid < T > ( addr : usize ) -> * const T {
591+ pub const fn without_provenance < T > ( addr : usize ) -> * const T {
592592 // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
593593 // We use transmute rather than a cast so tools like Miri can tell that this
594594 // is *not* the same as from_exposed_addr.
@@ -597,29 +597,40 @@ pub const fn invalid<T>(addr: usize) -> *const T {
597597 unsafe { mem:: transmute ( addr) }
598598}
599599
600- /// Creates an invalid mutable pointer with the given address .
600+ /// Creates a new pointer that is dangling, but well-aligned .
601601///
602- /// This is different from `addr as *mut T`, which creates a pointer that picks up a previously
603- /// exposed provenance. See [`from_exposed_addr_mut`] for more details on that operation .
602+ /// This is useful for initializing types which lazily allocate, like
603+ /// `Vec::new` does .
604604///
605- /// The module's top-level documentation discusses the precise meaning of an "invalid"
606- /// pointer but essentially this expresses that the pointer is not associated
607- /// with any actual allocation and is little more than a usize address in disguise.
605+ /// Note that the pointer value may potentially represent a valid pointer to
606+ /// a `T`, which means this must not be used as a "not yet initialized"
607+ /// sentinel value. Types that lazily allocate must track initialization by
608+ /// some other means.
609+ #[ inline( always) ]
610+ #[ must_use]
611+ #[ rustc_const_stable( feature = "stable_things_using_strict_provenance" , since = "1.61.0" ) ]
612+ #[ unstable( feature = "strict_provenance" , issue = "95228" ) ]
613+ pub const fn dangling < T > ( ) -> * const T {
614+ without_provenance ( mem:: align_of :: < T > ( ) )
615+ }
616+
617+ /// Creates a pointer with the given address and no provenance.
608618///
609- /// This pointer will have no provenance associated with it and is therefore
610- /// UB to read/write/offset. This mostly exists to facilitate things
611- /// like `ptr::null` and `NonNull::dangling` which make invalid pointers.
619+ /// Without provenance, this pointer is not associated with any actual allocation. Such a
620+ /// no-provenance pointer may be used for zero-sized memory accesses (if suitably aligned), but
621+ /// non-zero-sized memory accesses with a no-provenance pointer are UB. No-provenance pointers are
622+ /// little more than a usize address in disguise.
612623///
613- /// (Standard "Zero-Sized-Types get to cheat and lie" caveats apply, although it
614- /// may be desirable to give them their own API just to make that 100% clear.)
624+ /// This is different from `addr as *mut T`, which creates a pointer that picks up a previously
625+ /// exposed provenance. See [`from_exposed_addr_mut`] for more details on that operation.
615626///
616627/// This API and its claimed semantics are part of the Strict Provenance experiment,
617628/// see the [module documentation][crate::ptr] for details.
618629#[ inline( always) ]
619630#[ must_use]
620631#[ rustc_const_stable( feature = "stable_things_using_strict_provenance" , since = "1.61.0" ) ]
621632#[ unstable( feature = "strict_provenance" , issue = "95228" ) ]
622- pub const fn invalid_mut < T > ( addr : usize ) -> * mut T {
633+ pub const fn without_provenance_mut < T > ( addr : usize ) -> * mut T {
623634 // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
624635 // We use transmute rather than a cast so tools like Miri can tell that this
625636 // is *not* the same as from_exposed_addr.
@@ -628,6 +639,23 @@ pub const fn invalid_mut<T>(addr: usize) -> *mut T {
628639 unsafe { mem:: transmute ( addr) }
629640}
630641
642+ /// Creates a new pointer that is dangling, but well-aligned.
643+ ///
644+ /// This is useful for initializing types which lazily allocate, like
645+ /// `Vec::new` does.
646+ ///
647+ /// Note that the pointer value may potentially represent a valid pointer to
648+ /// a `T`, which means this must not be used as a "not yet initialized"
649+ /// sentinel value. Types that lazily allocate must track initialization by
650+ /// some other means.
651+ #[ inline( always) ]
652+ #[ must_use]
653+ #[ rustc_const_stable( feature = "stable_things_using_strict_provenance" , since = "1.61.0" ) ]
654+ #[ unstable( feature = "strict_provenance" , issue = "95228" ) ]
655+ pub const fn dangling_mut < T > ( ) -> * mut T {
656+ without_provenance_mut ( mem:: align_of :: < T > ( ) )
657+ }
658+
631659/// Convert an address back to a pointer, picking up a previously 'exposed' provenance.
632660///
633661/// This is a more rigorously specified alternative to `addr as *const T`. The provenance of the
0 commit comments