Skip to content

Commit 8310380

Browse files
authored
Rollup merge of rust-lang#146324 - RalfJung:no-ptr-fragment, r=oli-obk
const-eval: disable pointer fragment support This fixes rust-lang#146291 by disabling pointer fragment support for const-eval. I want to properly fix this eventually, but won't get to it in the next few weeks, so this is an emergency patch to prevent the buggy implementation from landing on stable. The beta cutoff is on Sep 12th so if this PR lands after that, we'll need a backport.
2 parents 67c44c7 + fd600c2 commit 8310380

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

core/src/ptr/mod.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,40 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
13481348
/// assert_eq!(x, [7, 8, 3, 4]);
13491349
/// assert_eq!(y, [1, 2, 9]);
13501350
/// ```
1351+
///
1352+
/// # Const evaluation limitations
1353+
///
1354+
/// If this function is invoked during const-evaluation, the current implementation has a small (and
1355+
/// rarely relevant) limitation: if `count` is at least 2 and the data pointed to by `x` or `y`
1356+
/// contains a pointer that crosses the boundary of two `T`-sized chunks of memory, the function may
1357+
/// fail to evaluate (similar to a panic during const-evaluation). This behavior may change in the
1358+
/// future.
1359+
///
1360+
/// The limitation is illustrated by the following example:
1361+
///
1362+
/// ```
1363+
/// use std::mem::size_of;
1364+
/// use std::ptr;
1365+
///
1366+
/// const { unsafe {
1367+
/// const PTR_SIZE: usize = size_of::<*const i32>();
1368+
/// let mut data1 = [0u8; PTR_SIZE];
1369+
/// let mut data2 = [0u8; PTR_SIZE];
1370+
/// // Store a pointer in `data1`.
1371+
/// data1.as_mut_ptr().cast::<*const i32>().write_unaligned(&42);
1372+
/// // Swap the contents of `data1` and `data2` by swapping `PTR_SIZE` many `u8`-sized chunks.
1373+
/// // This call will fail, because the pointer in `data1` crosses the boundary
1374+
/// // between several of the 1-byte chunks that are being swapped here.
1375+
/// //ptr::swap_nonoverlapping(data1.as_mut_ptr(), data2.as_mut_ptr(), PTR_SIZE);
1376+
/// // Swap the contents of `data1` and `data2` by swapping a single chunk of size
1377+
/// // `[u8; PTR_SIZE]`. That works, as there is no pointer crossing the boundary between
1378+
/// // two chunks.
1379+
/// ptr::swap_nonoverlapping(&mut data1, &mut data2, 1);
1380+
/// // Read the pointer from `data2` and dereference it.
1381+
/// let ptr = data2.as_ptr().cast::<*const i32>().read_unaligned();
1382+
/// assert!(*ptr == 42);
1383+
/// } }
1384+
/// ```
13511385
#[inline]
13521386
#[stable(feature = "swap_nonoverlapping", since = "1.27.0")]
13531387
#[rustc_const_stable(feature = "const_swap_nonoverlapping", since = "1.88.0")]
@@ -1376,7 +1410,9 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
13761410
const_eval_select!(
13771411
@capture[T] { x: *mut T, y: *mut T, count: usize }:
13781412
if const {
1379-
// At compile-time we don't need all the special code below.
1413+
// At compile-time we want to always copy this in chunks of `T`, to ensure that if there
1414+
// are pointers inside `T` we will copy them in one go rather than trying to copy a part
1415+
// of a pointer (which would not work).
13801416
// SAFETY: Same preconditions as this function
13811417
unsafe { swap_nonoverlapping_const(x, y, count) }
13821418
} else {

coretests/tests/ptr.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -936,12 +936,13 @@ fn test_const_swap_ptr() {
936936
assert!(*s1.0.ptr == 666);
937937
assert!(*s2.0.ptr == 1);
938938

939-
// Swap them back, byte-for-byte
939+
// Swap them back, again as an array.
940+
// FIXME(#146291): we should be swapping back at type `u8` but that currently does not work.
940941
unsafe {
941942
ptr::swap_nonoverlapping(
942-
ptr::from_mut(&mut s1).cast::<u8>(),
943-
ptr::from_mut(&mut s2).cast::<u8>(),
944-
size_of::<A>(),
943+
ptr::from_mut(&mut s1).cast::<T>(),
944+
ptr::from_mut(&mut s2).cast::<T>(),
945+
1,
945946
);
946947
}
947948

0 commit comments

Comments
 (0)