Skip to content

Commit 651db87

Browse files
authored
Rollup merge of #149169 - RalfJung:replace-zst-null-ptr, r=Mark-Simulacrum
ptr::replace: make calls on ZST null ptr not UB See #138351 for context. We made `ptr::read` and `ptr::write` not UB on ZST null pointers. This does the same with `ptr::replace`. Since we're just adding a branch on a constant, this should come at no runtime cost.
2 parents 859951e + 2484cfe commit 651db87

1 file changed

Lines changed: 8 additions & 1 deletion

File tree

library/core/src/ptr/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1543,7 +1543,7 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T {
15431543
// SAFETY: the caller must guarantee that `dst` is valid to be
15441544
// cast to a mutable reference (valid for writes, aligned, initialized),
15451545
// and cannot overlap `src` since `dst` must point to a distinct
1546-
// allocation.
1546+
// allocation. We are excluding null (with a ZST check) before creating a reference.
15471547
unsafe {
15481548
ub_checks::assert_unsafe_precondition!(
15491549
check_language_ub,
@@ -1554,6 +1554,13 @@ pub const unsafe fn replace<T>(dst: *mut T, src: T) -> T {
15541554
is_zst: bool = T::IS_ZST,
15551555
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
15561556
);
1557+
if T::IS_ZST {
1558+
// `dst` may be valid for read and writes while also being null, in which case we cannot
1559+
// call `mem::replace`. However, we also don't have to actually do anything since there
1560+
// isn't actually any data to be copied anyway. All values of type `T` are
1561+
// bit-identical, so we can just return `src` here.
1562+
return src;
1563+
}
15571564
mem::replace(&mut *dst, src)
15581565
}
15591566
}

0 commit comments

Comments
 (0)