diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 24c1fe43d0c..ca1106384fd 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -700,8 +700,13 @@ fn copy_op_no_validate( assert_eq!(src.layout.size, dest.layout.size); } + // Setting `nonoverlapping` here only has an effect when we don't hit the fast-path above, + // but that should at least match what LLVM does where `memcpy` is also only used when the + // type does not have Scalar/ScalarPair layout. + // (Or as the `Assign` docs put it, assignments "not producing primitives" must be + // non-overlapping.) self.mem_copy( - src.ptr, src.align, dest.ptr, dest.align, dest_size, /*nonoverlapping*/ false, + src.ptr, src.align, dest.ptr, dest.align, dest_size, /*nonoverlapping*/ true, ) } diff --git a/src/tools/miri/tests/fail/overlapping_assignment.rs b/src/tools/miri/tests/fail/overlapping_assignment.rs new file mode 100644 index 00000000000..84994c179f9 --- /dev/null +++ b/src/tools/miri/tests/fail/overlapping_assignment.rs @@ -0,0 +1,23 @@ +#![feature(core_intrinsics)] +#![feature(custom_mir)] + +use std::intrinsics::mir::*; + +// It's not that easy to fool the MIR validity check +// which wants to prevent overlapping assignments... +// So we use two separate pointer arguments, and then arrange for them to alias. +#[custom_mir(dialect = "runtime", phase = "optimized")] +pub fn self_copy(ptr1: *mut [i32; 4], ptr2: *mut [i32; 4]) { + mir! { + { + *ptr1 = *ptr2; //~ERROR: overlapping ranges + Return() + } + } +} + +pub fn main() { + let mut x = [0; 4]; + let ptr = std::ptr::addr_of_mut!(x); + self_copy(ptr, ptr); +} diff --git a/src/tools/miri/tests/fail/overlapping_assignment.stderr b/src/tools/miri/tests/fail/overlapping_assignment.stderr new file mode 100644 index 00000000000..42a000dfcc6 --- /dev/null +++ b/src/tools/miri/tests/fail/overlapping_assignment.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges + --> $DIR/overlapping_assignment.rs:LL:CC + | +LL | *ptr1 = *ptr2; + | ^^^^^^^^^^^^^ `copy_nonoverlapping` called on overlapping ranges + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `self_copy` at $DIR/overlapping_assignment.rs:LL:CC +note: inside `main` + --> $DIR/overlapping_assignment.rs:LL:CC + | +LL | self_copy(ptr, ptr); + | ^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error +