Skip to content

Commit b58f647

Browse files
committed
rename ptr::invalid -> ptr::without_provenance
also introduce ptr::dangling matching NonNull::dangling
1 parent 1d447a9 commit b58f647

File tree

56 files changed

+303
-232
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+303
-232
lines changed

compiler/rustc_arena/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl<T> ArenaChunk<T> {
9595
unsafe {
9696
if mem::size_of::<T>() == 0 {
9797
// A pointer as large as possible for zero-sized elements.
98-
ptr::invalid_mut(!0)
98+
ptr::without_provenance_mut(!0)
9999
} else {
100100
self.start().add(self.storage.len())
101101
}

library/alloc/src/rc.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -2804,7 +2804,9 @@ impl<T> Weak<T> {
28042804
#[must_use]
28052805
pub const fn new() -> Weak<T> {
28062806
Weak {
2807-
ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::<RcBox<T>>(usize::MAX)) },
2807+
ptr: unsafe {
2808+
NonNull::new_unchecked(ptr::without_provenance_mut::<RcBox<T>>(usize::MAX))
2809+
},
28082810
alloc: Global,
28092811
}
28102812
}
@@ -2829,7 +2831,9 @@ impl<T, A: Allocator> Weak<T, A> {
28292831
#[unstable(feature = "allocator_api", issue = "32838")]
28302832
pub fn new_in(alloc: A) -> Weak<T, A> {
28312833
Weak {
2832-
ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::<RcBox<T>>(usize::MAX)) },
2834+
ptr: unsafe {
2835+
NonNull::new_unchecked(ptr::without_provenance_mut::<RcBox<T>>(usize::MAX))
2836+
},
28332837
alloc,
28342838
}
28352839
}

library/alloc/src/sync.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -2555,7 +2555,9 @@ impl<T> Weak<T> {
25552555
#[must_use]
25562556
pub const fn new() -> Weak<T> {
25572557
Weak {
2558-
ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::<ArcInner<T>>(usize::MAX)) },
2558+
ptr: unsafe {
2559+
NonNull::new_unchecked(ptr::without_provenance_mut::<ArcInner<T>>(usize::MAX))
2560+
},
25592561
alloc: Global,
25602562
}
25612563
}
@@ -2583,7 +2585,9 @@ impl<T, A: Allocator> Weak<T, A> {
25832585
#[unstable(feature = "allocator_api", issue = "32838")]
25842586
pub fn new_in(alloc: A) -> Weak<T, A> {
25852587
Weak {
2586-
ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::<ArcInner<T>>(usize::MAX)) },
2588+
ptr: unsafe {
2589+
NonNull::new_unchecked(ptr::without_provenance_mut::<ArcInner<T>>(usize::MAX))
2590+
},
25872591
alloc,
25882592
}
25892593
}

library/alloc/tests/fmt.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,14 @@ fn test_format_macro_interface() {
7777
t!(format!("{}", "foo"), "foo");
7878
t!(format!("{}", "foo".to_string()), "foo");
7979
if cfg!(target_pointer_width = "32") {
80-
t!(format!("{:#p}", ptr::invalid::<isize>(0x1234)), "0x00001234");
81-
t!(format!("{:#p}", ptr::invalid_mut::<isize>(0x1234)), "0x00001234");
80+
t!(format!("{:#p}", ptr::without_provenance::<isize>(0x1234)), "0x00001234");
81+
t!(format!("{:#p}", ptr::without_provenance_mut::<isize>(0x1234)), "0x00001234");
8282
} else {
83-
t!(format!("{:#p}", ptr::invalid::<isize>(0x1234)), "0x0000000000001234");
84-
t!(format!("{:#p}", ptr::invalid_mut::<isize>(0x1234)), "0x0000000000001234");
83+
t!(format!("{:#p}", ptr::without_provenance::<isize>(0x1234)), "0x0000000000001234");
84+
t!(format!("{:#p}", ptr::without_provenance_mut::<isize>(0x1234)), "0x0000000000001234");
8585
}
86-
t!(format!("{:p}", ptr::invalid::<isize>(0x1234)), "0x1234");
87-
t!(format!("{:p}", ptr::invalid_mut::<isize>(0x1234)), "0x1234");
86+
t!(format!("{:p}", ptr::without_provenance::<isize>(0x1234)), "0x1234");
87+
t!(format!("{:p}", ptr::without_provenance_mut::<isize>(0x1234)), "0x1234");
8888
t!(format!("{A:x}"), "aloha");
8989
t!(format!("{B:X}"), "adios");
9090
t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
@@ -208,7 +208,7 @@ fn test_format_macro_interface() {
208208
{
209209
let val = usize::MAX;
210210
let exp = format!("{val:#x}");
211-
t!(format!("{:p}", std::ptr::invalid::<isize>(val)), exp);
211+
t!(format!("{:p}", std::ptr::without_provenance::<isize>(val)), exp);
212212
}
213213

214214
// Escaping

library/alloc/tests/vec.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2575,7 +2575,7 @@ fn test_box_zero_allocator() {
25752575
assert!(state.0.insert(addr));
25762576
state.1 += 1;
25772577
std::println!("allocating {addr}");
2578-
std::ptr::invalid_mut(addr)
2578+
std::ptr::without_provenance_mut(addr)
25792579
} else {
25802580
unsafe { std::alloc::alloc(layout) }
25812581
};

library/core/src/alloc/layout.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ impl Layout {
215215
#[inline]
216216
pub const fn dangling(&self) -> NonNull<u8> {
217217
// SAFETY: align is guaranteed to be non-zero
218-
unsafe { NonNull::new_unchecked(crate::ptr::invalid_mut::<u8>(self.align())) }
218+
unsafe { NonNull::new_unchecked(crate::ptr::without_provenance_mut::<u8>(self.align())) }
219219
}
220220

221221
/// Creates a layout describing the record that can hold a value

library/core/src/intrinsics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1155,7 +1155,7 @@ extern "rust-intrinsic" {
11551155
///
11561156
/// Transmuting pointers *to* integers in a `const` context is [undefined behavior][ub],
11571157
/// unless the pointer was originally created *from* an integer.
1158-
/// (That includes this function specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::invalid],
1158+
/// (That includes this function specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::dangling],
11591159
/// but also semantically-equivalent conversions such as punning through `repr(C)` union fields.)
11601160
/// Any attempt to use the resulting value for integer operations will abort const-evaluation.
11611161
/// (And even outside `const`, such transmutation is touching on many unspecified aspects of the

library/core/src/ptr/const_ptr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ impl<T: ?Sized> *const T {
181181
///
182182
/// This is similar to `self as usize`, which semantically discards *provenance* and
183183
/// *address-space* information. However, unlike `self as usize`, casting the returned address
184-
/// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To
184+
/// back to a pointer yields a [pointer without provenance][without_provenance], which is undefined behavior to dereference. To
185185
/// properly restore the lost information and obtain a dereferenceable pointer, use
186186
/// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
187187
///

library/core/src/ptr/mod.rs

+71-43
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
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:
@@ -26,7 +26,7 @@
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
@@ -44,6 +44,10 @@
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
@@ -167,6 +171,7 @@
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
@@ -270,11 +275,12 @@
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
@@ -283,7 +289,7 @@
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
@@ -294,7 +300,7 @@
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
@@ -367,7 +373,7 @@
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"]
539545
pub 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"]
565571
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), ())
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

library/core/src/ptr/mut_ptr.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,10 @@ impl<T: ?Sized> *mut T {
188188
///
189189
/// This is similar to `self as usize`, which semantically discards *provenance* and
190190
/// *address-space* information. However, unlike `self as usize`, casting the returned address
191-
/// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To
192-
/// properly restore the lost information and obtain a dereferenceable pointer, use
193-
/// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
191+
/// back to a pointer yields yields a [pointer without provenance][without_provenance_mut], which is undefined
192+
/// behavior to dereference. To properly restore the lost information and obtain a
193+
/// dereferenceable pointer, use [`with_addr`][pointer::with_addr] or
194+
/// [`map_addr`][pointer::map_addr].
194195
///
195196
/// If using those APIs is not possible because there is no way to preserve a pointer with the
196197
/// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts

library/core/src/ptr/non_null.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ use crate::hash;
44
use crate::intrinsics;
55
use crate::intrinsics::assert_unsafe_precondition;
66
use crate::marker::Unsize;
7-
use crate::mem::SizedTypeProperties;
8-
use crate::mem::{self, MaybeUninit};
7+
use crate::mem::{MaybeUninit, SizedTypeProperties};
98
use crate::num::{NonZero, NonZeroUsize};
109
use crate::ops::{CoerceUnsized, DispatchFromDyn};
1110
use crate::ptr;
@@ -114,7 +113,7 @@ impl<T: Sized> NonNull<T> {
114113
// to a *mut T. Therefore, `ptr` is not null and the conditions for
115114
// calling new_unchecked() are respected.
116115
unsafe {
117-
let ptr = crate::ptr::invalid_mut::<T>(mem::align_of::<T>());
116+
let ptr = crate::ptr::dangling_mut::<T>();
118117
NonNull::new_unchecked(ptr)
119118
}
120119
}

0 commit comments

Comments
 (0)