diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 9c032c55fe544..ded4253edc209 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1096,23 +1096,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The pointers above remain valid even if the `HashMap` table is moved around because they // point into the `Vec` storing the bytes. unsafe { - if src_alloc_id == dest_alloc_id { + if Self::check_ptr_overlap(src_alloc_id, src_offset, dest_alloc_id, dest_offset, size) { if nonoverlapping { - // `Size` additions - if (src_offset <= dest_offset && src_offset + size > dest_offset) - || (dest_offset <= src_offset && dest_offset + size > src_offset) - { - throw_ub_format!("copy_nonoverlapping called on overlapping ranges") + throw_ub_format!("copy_nonoverlapping called on overlapping ranges") + } else { + for i in 0..num_copies { + ptr::copy( + src_bytes, + dest_bytes.add((size * i).bytes_usize()), // `Size` multiplication + size.bytes_usize(), + ); } } - - for i in 0..num_copies { - ptr::copy( - src_bytes, - dest_bytes.add((size * i).bytes_usize()), // `Size` multiplication - size.bytes_usize(), - ); - } } else { for i in 0..num_copies { ptr::copy_nonoverlapping( @@ -1211,4 +1206,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into() }) } + + /// Check if a `src` ptr overlaps with a `dest` ptr. + #[inline(always)] + pub fn check_ptr_overlap( + src_id: AllocId, + src_offset: Size, + dest_id: AllocId, + dest_offset: Size, + size: Size, + ) -> bool { + let overlaps = |a, b| a <= b && b - a < size; + src_id == dest_id + && (overlaps(src_offset, dest_offset) || overlaps(dest_offset, src_offset)) + } } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 955480a1a7411..3e57214caf30c 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -4,6 +4,7 @@ use std::convert::TryFrom; use std::hash::Hash; +use std::ops::Deref; use rustc_ast::Mutability; use rustc_macros::HashStable; @@ -869,8 +870,20 @@ where Ok(src_val) => { assert!(!src.layout.is_unsized(), "cannot have unsized immediates"); // Yay, we got a value that we can write directly. - // FIXME: Add a check to make sure that if `src` is indirect, - // it does not overlap with `dest`. + let size = src_val.layout.size; + if size != Size::ZERO + && let Operand::Indirect(src_mplace) = src.deref() + && let Place::Ptr(dest_mplace) = dest.deref() + { + // If `src` and `dest` are both `MemPlace`, we need to check if the memory + // they point overlap. + let (src_id, src_offset, _) = self.ptr_get_alloc_id(src_mplace.ptr)?; + let (dest_id, dest_offset, _) = self.ptr_get_alloc_id(dest_mplace.ptr)?; + + if Self::check_ptr_overlap(src_id, src_offset, dest_id, dest_offset, size) { + throw_ub_format!("copy the operand to the overlapping place") + } + } return self.write_immediate_no_validate(*src_val, dest); } Err(mplace) => mplace,