Skip to content

Commit c7de289

Browse files
committed
Make the stdlib largely conform to strict provenance.
Some things like the unwinders and system APIs are not fully conformant, this only covers a lot of low-hanging fruit.
1 parent 5167b68 commit c7de289

File tree

30 files changed

+100
-81
lines changed

30 files changed

+100
-81
lines changed

library/alloc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
#![feature(rustc_allow_const_fn_unstable)]
159159
#![feature(rustc_attrs)]
160160
#![feature(staged_api)]
161+
#![feature(strict_provenance)]
161162
#![cfg_attr(test, feature(test))]
162163
#![feature(unboxed_closures)]
163164
#![feature(unsized_fn_params)]

library/alloc/src/rc.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,13 +2115,12 @@ impl<T> Weak<T> {
21152115
#[rustc_const_unstable(feature = "const_weak_new", issue = "95091", reason = "recently added")]
21162116
#[must_use]
21172117
pub const fn new() -> Weak<T> {
2118-
Weak { ptr: unsafe { NonNull::new_unchecked(usize::MAX as *mut RcBox<T>) } }
2118+
Weak { ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::<RcBox<T>>(usize::MAX)) } }
21192119
}
21202120
}
21212121

21222122
pub(crate) fn is_dangling<T: ?Sized>(ptr: *mut T) -> bool {
2123-
let address = ptr as *mut () as usize;
2124-
address == usize::MAX
2123+
(ptr as *mut ()).addr() == usize::MAX
21252124
}
21262125

21272126
/// Helper type to allow accessing the reference counts without

library/alloc/src/slice.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,7 @@ where
10441044
impl<T> Drop for MergeHole<T> {
10451045
fn drop(&mut self) {
10461046
// `T` is not a zero-sized type, so it's okay to divide by its size.
1047-
let len = (self.end as usize - self.start as usize) / mem::size_of::<T>();
1047+
let len = (self.end.addr() - self.start.addr()) / mem::size_of::<T>();
10481048
unsafe {
10491049
ptr::copy_nonoverlapping(self.start, self.dest, len);
10501050
}

library/alloc/src/sync.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1746,7 +1746,7 @@ impl<T> Weak<T> {
17461746
#[rustc_const_unstable(feature = "const_weak_new", issue = "95091", reason = "recently added")]
17471747
#[must_use]
17481748
pub const fn new() -> Weak<T> {
1749-
Weak { ptr: unsafe { NonNull::new_unchecked(usize::MAX as *mut ArcInner<T>) } }
1749+
Weak { ptr: unsafe { NonNull::new_unchecked(ptr::invalid_mut::<ArcInner<T>>(usize::MAX)) } }
17501750
}
17511751
}
17521752

library/alloc/src/vec/into_iter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
159159
#[inline]
160160
fn size_hint(&self) -> (usize, Option<usize>) {
161161
let exact = if mem::size_of::<T>() == 0 {
162-
(self.end as usize).wrapping_sub(self.ptr as usize)
162+
self.end.addr().wrapping_sub(self.ptr.addr())
163163
} else {
164164
unsafe { self.end.offset_from(self.ptr) as usize }
165165
};

library/core/src/alloc/layout.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ impl Layout {
194194
#[inline]
195195
pub const fn dangling(&self) -> NonNull<u8> {
196196
// SAFETY: align is guaranteed to be non-zero
197-
unsafe { NonNull::new_unchecked(self.align() as *mut u8) }
197+
unsafe { NonNull::new_unchecked(crate::ptr::invalid_mut::<u8>(self.align())) }
198198
}
199199

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

library/core/src/fmt/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,11 @@ impl<'a> ArgumentV1<'a> {
352352
}
353353

354354
fn as_usize(&self) -> Option<usize> {
355-
if self.formatter as usize == USIZE_MARKER as usize {
355+
// We are type punning a bit here: USIZE_MARKER only takes an &usize but
356+
// formatter takes an &Opaque. Rust understandably doesn't think we should compare
357+
// the function pointers if they don't have the same signature, so we cast to
358+
// pointers to convince it that we know what we're doing.
359+
if self.formatter as *mut u8 == USIZE_MARKER as *mut u8 {
356360
// SAFETY: The `formatter` field is only set to USIZE_MARKER if
357361
// the value is a usize, so this is safe
358362
Some(unsafe { *(self.value as *const _ as *const usize) })
@@ -2246,7 +2250,7 @@ impl<T: ?Sized> Pointer for *const T {
22462250
}
22472251
f.flags |= 1 << (FlagV1::Alternate as u32);
22482252

2249-
let ret = LowerHex::fmt(&(ptr as usize), f);
2253+
let ret = LowerHex::fmt(&(ptr.addr()), f);
22502254

22512255
f.width = old_width;
22522256
f.flags = old_flags;

library/core/src/hash/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ mod impls {
793793
#[inline]
794794
fn hash<H: Hasher>(&self, state: &mut H) {
795795
let (address, metadata) = self.to_raw_parts();
796-
state.write_usize(address as usize);
796+
state.write_usize(address.addr());
797797
metadata.hash(state);
798798
}
799799
}
@@ -803,7 +803,7 @@ mod impls {
803803
#[inline]
804804
fn hash<H: Hasher>(&self, state: &mut H) {
805805
let (address, metadata) = self.to_raw_parts();
806-
state.write_usize(address as usize);
806+
state.write_usize(address.addr());
807807
metadata.hash(state);
808808
}
809809
}

library/core/src/intrinsics.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1972,15 +1972,15 @@ extern "rust-intrinsic" {
19721972
/// Checks whether `ptr` is properly aligned with respect to
19731973
/// `align_of::<T>()`.
19741974
pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
1975-
!ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0
1975+
!ptr.is_null() && ptr.addr() % mem::align_of::<T>() == 0
19761976
}
19771977

19781978
/// Checks whether the regions of memory starting at `src` and `dst` of size
19791979
/// `count * size_of::<T>()` do *not* overlap.
19801980
#[cfg(debug_assertions)]
19811981
pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
1982-
let src_usize = src as usize;
1983-
let dst_usize = dst as usize;
1982+
let src_usize = src.addr();
1983+
let dst_usize = dst.addr();
19841984
let size = mem::size_of::<T>().checked_mul(count).unwrap();
19851985
let diff = if src_usize > dst_usize { src_usize - dst_usize } else { dst_usize - src_usize };
19861986
// If the absolute distance between the ptrs is at least as big as the size of the buffer,

library/core/src/ptr/non_null.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl<T: Sized> NonNull<T> {
9090
// to a *mut T. Therefore, `ptr` is not null and the conditions for
9191
// calling new_unchecked() are respected.
9292
unsafe {
93-
let ptr = mem::align_of::<T>() as *mut T;
93+
let ptr = crate::ptr::invalid_mut::<T>(mem::align_of::<T>());
9494
NonNull::new_unchecked(ptr)
9595
}
9696
}
@@ -469,7 +469,7 @@ impl<T> NonNull<[T]> {
469469
/// use std::ptr::NonNull;
470470
///
471471
/// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
472-
/// assert_eq!(slice.as_non_null_ptr(), NonNull::new(1 as *mut i8).unwrap());
472+
/// assert_eq!(slice.as_non_null_ptr(), NonNull::<i8>::dangling());
473473
/// ```
474474
#[inline]
475475
#[must_use]
@@ -489,7 +489,7 @@ impl<T> NonNull<[T]> {
489489
/// use std::ptr::NonNull;
490490
///
491491
/// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
492-
/// assert_eq!(slice.as_mut_ptr(), 1 as *mut i8);
492+
/// assert_eq!(slice.as_mut_ptr(), NonNull::<i8>::dangling().as_ptr());
493493
/// ```
494494
#[inline]
495495
#[must_use]

library/core/src/ptr/unique.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl<T: Sized> Unique<T> {
7373
pub const fn dangling() -> Self {
7474
// SAFETY: mem::align_of() returns a valid, non-null pointer. The
7575
// conditions to call new_unchecked() are thus respected.
76-
unsafe { Unique::new_unchecked(mem::align_of::<T>() as *mut T) }
76+
unsafe { Unique::new_unchecked(crate::ptr::invalid_mut::<T>(mem::align_of::<T>())) }
7777
}
7878
}
7979

library/core/src/slice/ascii.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -294,17 +294,17 @@ fn is_ascii(s: &[u8]) -> bool {
294294
// Paranoia check about alignment, since we're about to do a bunch of
295295
// unaligned loads. In practice this should be impossible barring a bug in
296296
// `align_offset` though.
297-
debug_assert_eq!((word_ptr as usize) % mem::align_of::<usize>(), 0);
297+
debug_assert_eq!((word_ptr.addr()) % mem::align_of::<usize>(), 0);
298298

299299
// Read subsequent words until the last aligned word, excluding the last
300300
// aligned word by itself to be done in tail check later, to ensure that
301301
// tail is always one `usize` at most to extra branch `byte_pos == len`.
302302
while byte_pos < len - USIZE_SIZE {
303303
debug_assert!(
304304
// Sanity check that the read is in bounds
305-
(word_ptr as usize + USIZE_SIZE) <= (start.wrapping_add(len) as usize) &&
305+
(word_ptr.addr() + USIZE_SIZE) <= (start.wrapping_add(len).addr()) &&
306306
// And that our assumptions about `byte_pos` hold.
307-
(word_ptr as usize) - (start as usize) == byte_pos
307+
(word_ptr.addr()) - (start.addr()) == byte_pos
308308
);
309309

310310
// SAFETY: We know `word_ptr` is properly aligned (because of

library/core/src/slice/iter/macros.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ macro_rules! len {
2020
if size == 0 {
2121
// This _cannot_ use `unchecked_sub` because we depend on wrapping
2222
// to represent the length of long ZST slice iterators.
23-
($self.end as usize).wrapping_sub(start.as_ptr() as usize)
23+
($self.end.addr()).wrapping_sub(start.as_ptr().addr())
2424
} else {
2525
// We know that `start <= end`, so can do better than `offset_from`,
2626
// which needs to deal in signed. By setting appropriate flags here
2727
// we can tell LLVM this, which helps it remove bounds checks.
2828
// SAFETY: By the type invariant, `start <= end`
29-
let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) };
29+
let diff = unsafe { unchecked_sub($self.end.addr(), start.as_ptr().addr()) };
3030
// By also telling LLVM that the pointers are apart by an exact
3131
// multiple of the type size, it can optimize `len() == 0` down to
3232
// `start == end` instead of `(end - start) < size`.

library/core/src/slice/sort.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ where
269269
// Returns the number of elements between pointers `l` (inclusive) and `r` (exclusive).
270270
fn width<T>(l: *mut T, r: *mut T) -> usize {
271271
assert!(mem::size_of::<T>() > 0);
272-
(r as usize - l as usize) / mem::size_of::<T>()
272+
(r.addr() - l.addr()) / mem::size_of::<T>()
273273
}
274274

275275
loop {

library/std/src/backtrace.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ impl Backtrace {
293293
if !Backtrace::enabled() {
294294
return Backtrace { inner: Inner::Disabled };
295295
}
296-
Backtrace::create(Backtrace::capture as usize)
296+
Backtrace::create((Backtrace::capture as *mut ()).addr())
297297
}
298298

299299
/// Forcibly captures a full backtrace, regardless of environment variable
@@ -308,7 +308,7 @@ impl Backtrace {
308308
/// parts of code.
309309
#[inline(never)] // want to make sure there's a frame here to remove
310310
pub fn force_capture() -> Backtrace {
311-
Backtrace::create(Backtrace::force_capture as usize)
311+
Backtrace::create((Backtrace::force_capture as *mut ()).addr())
312312
}
313313

314314
/// Forcibly captures a disabled backtrace, regardless of environment
@@ -330,7 +330,7 @@ impl Backtrace {
330330
frame: RawFrame::Actual(frame.clone()),
331331
symbols: Vec::new(),
332332
});
333-
if frame.symbol_address() as usize == ip && actual_start.is_none() {
333+
if frame.symbol_address().addr() == ip && actual_start.is_none() {
334334
actual_start = Some(frames.len());
335335
}
336336
true
@@ -493,7 +493,7 @@ impl RawFrame {
493493
match self {
494494
RawFrame::Actual(frame) => frame.ip(),
495495
#[cfg(test)]
496-
RawFrame::Fake => 1 as *mut c_void,
496+
RawFrame::Fake => ptr::invalid_mut(1),
497497
}
498498
}
499499
}

library/std/src/io/error/repr_bitpacked.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
106106
use alloc::boxed::Box;
107107
use core::marker::PhantomData;
108108
use core::mem::{align_of, size_of};
109-
use core::ptr::NonNull;
109+
use core::ptr::{self, NonNull};
110110

111111
// The 2 least-significant bits are used as tag.
112112
const TAG_MASK: usize = 0b11;
@@ -136,7 +136,7 @@ impl Repr {
136136
let p = Box::into_raw(b).cast::<u8>();
137137
// Should only be possible if an allocator handed out a pointer with
138138
// wrong alignment.
139-
debug_assert_eq!((p as usize & TAG_MASK), 0);
139+
debug_assert_eq!((p.addr() & TAG_MASK), 0);
140140
// Note: We know `TAG_CUSTOM <= size_of::<Custom>()` (static_assert at
141141
// end of file), and both the start and end of the expression must be
142142
// valid without address space wraparound due to `Box`'s semantics.
@@ -166,7 +166,7 @@ impl Repr {
166166
pub(super) fn new_os(code: i32) -> Self {
167167
let utagged = ((code as usize) << 32) | TAG_OS;
168168
// Safety: `TAG_OS` is not zero, so the result of the `|` is not 0.
169-
let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData);
169+
let res = Self(unsafe { NonNull::new_unchecked(ptr::invalid_mut(utagged)) }, PhantomData);
170170
// quickly smoke-check we encoded the right thing (This generally will
171171
// only run in libstd's tests, unless the user uses -Zbuild-std)
172172
debug_assert!(
@@ -180,7 +180,7 @@ impl Repr {
180180
pub(super) fn new_simple(kind: ErrorKind) -> Self {
181181
let utagged = ((kind as usize) << 32) | TAG_SIMPLE;
182182
// Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0.
183-
let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) }, PhantomData);
183+
let res = Self(unsafe { NonNull::new_unchecked(ptr::invalid_mut(utagged)) }, PhantomData);
184184
// quickly smoke-check we encoded the right thing (This generally will
185185
// only run in libstd's tests, unless the user uses -Zbuild-std)
186186
debug_assert!(
@@ -238,7 +238,7 @@ unsafe fn decode_repr<C, F>(ptr: NonNull<()>, make_custom: F) -> ErrorData<C>
238238
where
239239
F: FnOnce(*mut Custom) -> C,
240240
{
241-
let bits = ptr.as_ptr() as usize;
241+
let bits = ptr.as_ptr().addr();
242242
match bits & TAG_MASK {
243243
TAG_OS => {
244244
let code = ((bits as i64) >> 32) as i32;

library/std/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@
275275
#![feature(extend_one)]
276276
#![feature(float_minimum_maximum)]
277277
#![feature(format_args_nl)]
278+
#![feature(strict_provenance)]
278279
#![feature(get_mut_unchecked)]
279280
#![feature(hashmap_internals)]
280281
#![feature(int_error_internals)]

library/std/src/os/windows/io/handle.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::fs;
99
use crate::io;
1010
use crate::marker::PhantomData;
1111
use crate::mem::forget;
12+
use crate::ptr;
1213
use crate::sys::c;
1314
use crate::sys::cvt;
1415
use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -182,7 +183,7 @@ impl OwnedHandle {
182183
return unsafe { Ok(Self::from_raw_handle(handle)) };
183184
}
184185

185-
let mut ret = 0 as c::HANDLE;
186+
let mut ret = ptr::null_mut();
186187
cvt(unsafe {
187188
let cur_proc = c::GetCurrentProcess();
188189
c::DuplicateHandle(

library/std/src/os/windows/io/socket.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ impl OwnedSocket {
129129
}
130130
}
131131

132+
// FIXME(strict_provenance_magic): we defined RawSocket to be a u64 ;-;
132133
#[cfg(not(target_vendor = "uwp"))]
133134
pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
134135
cvt(unsafe {

library/std/src/path.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1449,8 +1449,8 @@ impl PathBuf {
14491449
};
14501450

14511451
// truncate until right after the file stem
1452-
let end_file_stem = file_stem[file_stem.len()..].as_ptr() as usize;
1453-
let start = os_str_as_u8_slice(&self.inner).as_ptr() as usize;
1452+
let end_file_stem = file_stem[file_stem.len()..].as_ptr().addr();
1453+
let start = os_str_as_u8_slice(&self.inner).as_ptr().addr();
14541454
let v = self.as_mut_vec();
14551455
v.truncate(end_file_stem.wrapping_sub(start));
14561456

0 commit comments

Comments
 (0)