Skip to content

Commit a4d9624

Browse files
committed
Auto merge of #82967 - RalfJung:copy-nonoverlap, r=oli-obk
fix copy_nonoverlapping Fixes a bug introduced by #77511 r? `@oli-obk` Fixes #82961
2 parents dff1edf + 4d74862 commit a4d9624

File tree

3 files changed

+76
-7
lines changed

3 files changed

+76
-7
lines changed

compiler/rustc_mir/src/interpret/step.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
115115
}
116116

117117
// Call CopyNonOverlapping
118-
CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
119-
let count = self.eval_operand(count, None)?;
120-
118+
CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { src, dst, count }) => {
121119
let src = self.eval_operand(src, None)?;
122120
let dst = self.eval_operand(dst, None)?;
121+
let count = self.eval_operand(count, None)?;
123122
self.copy(&src, &dst, &count, /* nonoverlapping */ true)?;
124123
}
125124

@@ -160,16 +159,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
160159
let count = self.read_scalar(&count)?.to_machine_usize(self)?;
161160
let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
162161
let (size, align) = (layout.size, layout.align.abi);
162+
let size = size.checked_mul(count, self).ok_or_else(|| {
163+
err_ub_format!("overflow computing total size of `copy_nonoverlapping`")
164+
})?;
165+
166+
// Make sure we check both pointers for an access of the total size and aligment,
167+
// *even if* the total size is 0.
163168
let src =
164169
self.memory.check_ptr_access(self.read_scalar(&src)?.check_init()?, size, align)?;
165170

166171
let dst =
167172
self.memory.check_ptr_access(self.read_scalar(&dst)?.check_init()?, size, align)?;
168173

169-
let size = size.checked_mul(count, self).ok_or_else(|| {
170-
err_ub_format!("overflow computing total size of `copy_nonoverlapping`")
171-
})?;
172-
173174
if let (Some(src), Some(dst)) = (src, dst) {
174175
self.memory.copy(src, dst, size, nonoverlapping)?;
175176
}

src/test/ui/consts/copy-intrinsic.rs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// ignore-tidy-linelength
2+
#![feature(const_mut_refs, const_intrinsic_copy, const_ptr_offset)]
3+
use std::ptr;
4+
5+
const COPY_ZERO: () = unsafe {
6+
// Since we are not copying anything, this should be allowed.
7+
let src = ();
8+
let mut dst = ();
9+
ptr::copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0);
10+
};
11+
12+
const COPY_OOB_1: () = unsafe {
13+
let mut x = 0i32;
14+
let dangle = (&mut x as *mut i32).wrapping_add(10);
15+
// Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs.
16+
ptr::copy_nonoverlapping(0x100 as *const i32, dangle, 0); //~ ERROR any use of this value will cause an error
17+
//~| memory access failed: pointer must be in-bounds
18+
//~| previously accepted
19+
};
20+
const COPY_OOB_2: () = unsafe {
21+
let x = 0i32;
22+
let dangle = (&x as *const i32).wrapping_add(10);
23+
// Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs.
24+
ptr::copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); //~ ERROR any use of this value will cause an error
25+
//~| memory access failed: pointer must be in-bounds
26+
//~| previously accepted
27+
};
28+
29+
30+
fn main() {
31+
}
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
error: any use of this value will cause an error
2+
--> $DIR/copy-intrinsic.rs:16:5
3+
|
4+
LL | / const COPY_OOB_1: () = unsafe {
5+
LL | | let mut x = 0i32;
6+
LL | | let dangle = (&mut x as *mut i32).wrapping_add(10);
7+
LL | | // Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs.
8+
LL | | ptr::copy_nonoverlapping(0x100 as *const i32, dangle, 0);
9+
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc4 which has size 4
10+
LL | |
11+
LL | |
12+
LL | | };
13+
| |__-
14+
|
15+
= note: `#[deny(const_err)]` on by default
16+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
17+
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
18+
19+
error: any use of this value will cause an error
20+
--> $DIR/copy-intrinsic.rs:24:5
21+
|
22+
LL | / const COPY_OOB_2: () = unsafe {
23+
LL | | let x = 0i32;
24+
LL | | let dangle = (&x as *const i32).wrapping_add(10);
25+
LL | | // Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs.
26+
LL | | ptr::copy_nonoverlapping(dangle, 0x100 as *mut i32, 0);
27+
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc6 which has size 4
28+
LL | |
29+
LL | |
30+
LL | | };
31+
| |__-
32+
|
33+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
34+
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
35+
36+
error: aborting due to 2 previous errors
37+

0 commit comments

Comments
 (0)