Skip to content

Commit 2668b2a

Browse files
committed
add overlap check when copying an imm
1 parent e838059 commit 2668b2a

File tree

2 files changed

+35
-16
lines changed

2 files changed

+35
-16
lines changed

compiler/rustc_const_eval/src/interpret/memory.rs

+23-14
Original file line numberDiff line numberDiff line change
@@ -1096,23 +1096,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
10961096
// The pointers above remain valid even if the `HashMap` table is moved around because they
10971097
// point into the `Vec` storing the bytes.
10981098
unsafe {
1099-
if src_alloc_id == dest_alloc_id {
1099+
if Self::check_ptr_overlap(src_alloc_id, src_offset, dest_alloc_id, dest_offset, size) {
11001100
if nonoverlapping {
1101-
// `Size` additions
1102-
if (src_offset <= dest_offset && src_offset + size > dest_offset)
1103-
|| (dest_offset <= src_offset && dest_offset + size > src_offset)
1104-
{
1105-
throw_ub_format!("copy_nonoverlapping called on overlapping ranges")
1101+
throw_ub_format!("copy_nonoverlapping called on overlapping ranges")
1102+
} else {
1103+
for i in 0..num_copies {
1104+
ptr::copy(
1105+
src_bytes,
1106+
dest_bytes.add((size * i).bytes_usize()), // `Size` multiplication
1107+
size.bytes_usize(),
1108+
);
11061109
}
11071110
}
1108-
1109-
for i in 0..num_copies {
1110-
ptr::copy(
1111-
src_bytes,
1112-
dest_bytes.add((size * i).bytes_usize()), // `Size` multiplication
1113-
size.bytes_usize(),
1114-
);
1115-
}
11161111
} else {
11171112
for i in 0..num_copies {
11181113
ptr::copy_nonoverlapping(
@@ -1211,4 +1206,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
12111206
err_ub!(DanglingIntPointer(offset, CheckInAllocMsg::InboundsTest)).into()
12121207
})
12131208
}
1209+
1210+
/// Check if a `src` ptr overlaps with a `dest` ptr.
1211+
#[inline(always)]
1212+
pub fn check_ptr_overlap(
1213+
src_id: AllocId,
1214+
src_offset: Size,
1215+
dest_id: AllocId,
1216+
dest_offset: Size,
1217+
size: Size,
1218+
) -> bool {
1219+
let overlaps = |a, b| a <= b && b < a + size;
1220+
src_id == dest_id
1221+
&& (overlaps(src_offset, dest_offset) || overlaps(dest_offset, src_offset))
1222+
}
12141223
}

compiler/rustc_const_eval/src/interpret/place.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
use std::convert::TryFrom;
66
use std::hash::Hash;
7+
use std::ops::Deref;
78

89
use rustc_ast::Mutability;
910
use rustc_macros::HashStable;
@@ -869,8 +870,17 @@ where
869870
Ok(src_val) => {
870871
assert!(!src.layout.is_unsized(), "cannot have unsized immediates");
871872
// Yay, we got a value that we can write directly.
872-
// FIXME: Add a check to make sure that if `src` is indirect,
873-
// it does not overlap with `dest`.
873+
// Then make sure `src` does not overlap with `dest`.
874+
if let Operand::Indirect(src_mplace) = src.deref()
875+
&& let Place::Ptr(dest_mplace) = dest.deref()
876+
&& let Ok((src_id, src_offset, _)) = self.ptr_try_get_alloc_id(src_mplace.ptr)
877+
&& let Ok((dest_id, dest_offset, _)) = self.ptr_try_get_alloc_id(dest_mplace.ptr)
878+
{
879+
let size = src_val.layout.size;
880+
if Self::check_ptr_overlap(src_id, src_offset, dest_id, dest_offset, size) {
881+
throw_ub_format!("copy_nonoverlapping called on overlapping ranges")
882+
}
883+
}
874884
return self.write_immediate_no_validate(*src_val, dest);
875885
}
876886
Err(mplace) => mplace,

0 commit comments

Comments
 (0)