Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix copy_nonoverlapping #82967

Merged
merged 2 commits into from
Mar 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions compiler/rustc_mir/src/interpret/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}

// Call CopyNonOverlapping
CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
let count = self.eval_operand(count, None)?;

CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { src, dst, count }) => {
let src = self.eval_operand(src, None)?;
let dst = self.eval_operand(dst, None)?;
let count = self.eval_operand(count, None)?;
self.copy(&src, &dst, &count, /* nonoverlapping */ true)?;
}

Expand Down Expand Up @@ -160,16 +159,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let count = self.read_scalar(&count)?.to_machine_usize(self)?;
let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
let (size, align) = (layout.size, layout.align.abi);
let size = size.checked_mul(count, self).ok_or_else(|| {
err_ub_format!("overflow computing total size of `copy_nonoverlapping`")
})?;

// Make sure we check both pointers for an access of the total size and aligment,
// *even if* the total size is 0.
let src =
self.memory.check_ptr_access(self.read_scalar(&src)?.check_init()?, size, align)?;

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

let size = size.checked_mul(count, self).ok_or_else(|| {
err_ub_format!("overflow computing total size of `copy_nonoverlapping`")
})?;

if let (Some(src), Some(dst)) = (src, dst) {
self.memory.copy(src, dst, size, nonoverlapping)?;
}
Expand Down
31 changes: 31 additions & 0 deletions src/test/ui/consts/copy-intrinsic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// ignore-tidy-linelength
#![feature(const_mut_refs, const_intrinsic_copy, const_ptr_offset)]
use std::ptr;

const COPY_ZERO: () = unsafe {
// Since we are not copying anything, this should be allowed.
let src = ();
let mut dst = ();
ptr::copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0);
};

const COPY_OOB_1: () = unsafe {
let mut x = 0i32;
let dangle = (&mut x as *mut i32).wrapping_add(10);
// Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs.
ptr::copy_nonoverlapping(0x100 as *const i32, dangle, 0); //~ ERROR any use of this value will cause an error
//~| memory access failed: pointer must be in-bounds
//~| previously accepted
};
const COPY_OOB_2: () = unsafe {
let x = 0i32;
let dangle = (&x as *const i32).wrapping_add(10);
// Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs.
ptr::copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); //~ ERROR any use of this value will cause an error
//~| memory access failed: pointer must be in-bounds
//~| previously accepted
};


fn main() {
}
37 changes: 37 additions & 0 deletions src/test/ui/consts/copy-intrinsic.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
error: any use of this value will cause an error
--> $DIR/copy-intrinsic.rs:16:5
|
LL | / const COPY_OOB_1: () = unsafe {
LL | | let mut x = 0i32;
LL | | let dangle = (&mut x as *mut i32).wrapping_add(10);
LL | | // Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs.
LL | | ptr::copy_nonoverlapping(0x100 as *const i32, dangle, 0);
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc4 which has size 4
LL | |
LL | |
LL | | };
| |__-
|
= note: `#[deny(const_err)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>

error: any use of this value will cause an error
--> $DIR/copy-intrinsic.rs:24:5
|
LL | / const COPY_OOB_2: () = unsafe {
LL | | let x = 0i32;
LL | | let dangle = (&x as *const i32).wrapping_add(10);
LL | | // Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs.
LL | | ptr::copy_nonoverlapping(dangle, 0x100 as *mut i32, 0);
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 40, but is outside bounds of alloc6 which has size 4
LL | |
LL | |
LL | | };
| |__-
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>

error: aborting due to 2 previous errors