4
4
//!
5
5
//! # Safety
6
6
//!
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.
14
14
//!
15
15
//! The precise rules for validity are not determined yet. The guarantees that are
16
16
//! provided at this point are very minimal:
26
26
//! some memory happens to exist at that address and gets deallocated. This corresponds to writing
27
27
//! your own allocator: allocating zero-sized objects is not very hard. The canonical way to
28
28
//! 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.
30
30
//! * All accesses performed by functions in this module are *non-atomic* in the sense
31
31
//! of [atomic operations] used to synchronize between threads. This means it is
32
32
//! undefined behavior to perform two concurrent accesses to the same location from different
44
44
//! information, see the [book] as well as the section in the reference devoted
45
45
//! to [undefined behavior][ub].
46
46
//!
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
+ //!
47
51
//! ## Alignment
48
52
//!
49
53
//! Valid raw pointers as defined above are not necessarily properly aligned (where
167
171
//! * The **address-space** it is part of (e.g. "data" vs "code" in WASM).
168
172
//! * The **address** it points to, which can be represented by a `usize`.
169
173
//! * 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.
170
175
//!
171
176
//! Under Strict Provenance, a usize *cannot* accurately represent a pointer, and converting from
172
177
//! a pointer to a usize is generally an operation which *only* extracts the address. It is
270
275
//!
271
276
//! But it *is* still sound to:
272
277
//!
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).
278
284
//!
279
285
//! * Forge an allocation of size zero at any sufficiently aligned non-null address.
280
286
//! i.e. the usual "ZSTs are fake, do what you want" rules apply *but* this only applies
283
289
//! that allocation and it will still get invalidated if the allocation gets deallocated.
284
290
//! In the future we may introduce an API to make such a forged allocation explicit.
285
291
//!
286
- //! * [`wrapping_offset`][] a pointer outside its provenance. This includes invalid pointers
292
+ //! * [`wrapping_offset`][] a pointer outside its provenance. This includes pointers
287
293
//! which have "no" provenance. Unfortunately there may be practical limits on this for a
288
294
//! particular platform, and it's an open question as to how to specify this (if at all).
289
295
//! Notably, [CHERI][] relies on a compression scheme that can't handle a
294
300
//! generous (think kilobytes, not bytes).
295
301
//!
296
302
//! * 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
298
304
//! address-spaces/provenances. Of course, comparing addresses from different address-spaces
299
305
//! is generally going to be *meaningless*, but so is comparing Kilograms to Meters, and Rust
300
306
//! doesn't prevent that either. Similarly, if you get "lucky" and notice that a pointer
367
373
//! [`with_addr`]: pointer::with_addr
368
374
//! [`map_addr`]: pointer::map_addr
369
375
//! [`addr`]: pointer::addr
370
- //! [`ptr::invalid `]: core::ptr::invalid
376
+ //! [`ptr::dangling `]: core::ptr::dangling
371
377
//! [`expose_addr`]: pointer::expose_addr
372
378
//! [`from_exposed_addr`]: from_exposed_addr
373
379
//! [Miri]: https://github.com/rust-lang/miri
@@ -537,7 +543,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
537
543
#[ rustc_allow_const_fn_unstable( ptr_metadata) ]
538
544
#[ rustc_diagnostic_item = "ptr_null" ]
539
545
pub const fn null < T : ?Sized + Thin > ( ) -> * const T {
540
- from_raw_parts ( invalid ( 0 ) , ( ) )
546
+ from_raw_parts ( without_provenance ( 0 ) , ( ) )
541
547
}
542
548
543
549
/// Creates a null mutable raw pointer.
@@ -563,32 +569,26 @@ pub const fn null<T: ?Sized + Thin>() -> *const T {
563
569
#[ rustc_allow_const_fn_unstable( ptr_metadata) ]
564
570
#[ rustc_diagnostic_item = "ptr_null_mut" ]
565
571
pub 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 ) , ( ) )
567
573
}
568
574
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.
570
581
///
571
582
/// This is different from `addr as *const T`, which creates a pointer that picks up a previously
572
583
/// exposed provenance. See [`from_exposed_addr`] for more details on that operation.
573
584
///
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
- ///
585
585
/// This API and its claimed semantics are part of the Strict Provenance experiment,
586
586
/// see the [module documentation][crate::ptr] for details.
587
587
#[ inline( always) ]
588
588
#[ must_use]
589
589
#[ rustc_const_stable( feature = "stable_things_using_strict_provenance" , since = "1.61.0" ) ]
590
590
#[ 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 {
592
592
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
593
593
// We use transmute rather than a cast so tools like Miri can tell that this
594
594
// is *not* the same as from_exposed_addr.
@@ -597,29 +597,40 @@ pub const fn invalid<T>(addr: usize) -> *const T {
597
597
unsafe { mem:: transmute ( addr) }
598
598
}
599
599
600
- /// Creates an invalid mutable pointer with the given address .
600
+ /// Creates a new pointer that is dangling, but well-aligned .
601
601
///
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 .
604
604
///
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.
608
618
///
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.
612
623
///
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.
615
626
///
616
627
/// This API and its claimed semantics are part of the Strict Provenance experiment,
617
628
/// see the [module documentation][crate::ptr] for details.
618
629
#[ inline( always) ]
619
630
#[ must_use]
620
631
#[ rustc_const_stable( feature = "stable_things_using_strict_provenance" , since = "1.61.0" ) ]
621
632
#[ 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 {
623
634
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
624
635
// We use transmute rather than a cast so tools like Miri can tell that this
625
636
// is *not* the same as from_exposed_addr.
@@ -628,6 +639,23 @@ pub const fn invalid_mut<T>(addr: usize) -> *mut T {
628
639
unsafe { mem:: transmute ( addr) }
629
640
}
630
641
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
+
631
659
/// Convert an address back to a pointer, picking up a previously 'exposed' provenance.
632
660
///
633
661
/// This is a more rigorously specified alternative to `addr as *const T`. The provenance of the
0 commit comments