From ffd482e2f5e5b5635922613500b13f0ba6150aaf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Jul 2017 20:27:09 -0700 Subject: [PATCH] check the assumptions made by the unchecked_ and copy_nonoverlapping intrinsics --- src/eval_context.rs | 2 +- src/memory.rs | 8 ++++++- src/terminator/intrinsic.rs | 15 ++++++++---- tests/compile-fail/copy_nonoverlapping.rs | 24 +++++++++++++++++++ tests/compile-fail/div-by-zero.rs | 21 ++++++++++++++++ .../compile-fail/overflowing-unchecked-rsh.rs | 21 ++++++++++++++++ 6 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 tests/compile-fail/copy_nonoverlapping.rs create mode 100644 tests/compile-fail/div-by-zero.rs create mode 100644 tests/compile-fail/overflowing-unchecked-rsh.rs diff --git a/src/eval_context.rs b/src/eval_context.rs index 630f878f7232..448ac2f70891 100644 --- a/src/eval_context.rs +++ b/src/eval_context.rs @@ -1022,7 +1022,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { fn copy(&mut self, src: PrimVal, dest: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx> { let size = self.type_size(ty)?.expect("cannot copy from an unsized type"); let align = self.type_align(ty)?; - self.memory.copy(src, dest, size, align)?; + self.memory.copy(src, dest, size, align, false)?; Ok(()) } diff --git a/src/memory.rs b/src/memory.rs index 638a8d2ff27c..7623a0c4d2e3 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -658,7 +658,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { Ok(()) } - pub fn copy(&mut self, src: PrimVal, dest: PrimVal, size: u64, align: u64) -> EvalResult<'tcx> { + pub fn copy(&mut self, src: PrimVal, dest: PrimVal, size: u64, align: u64, nonoverlapping: bool) -> EvalResult<'tcx> { if size == 0 { return Ok(()); } @@ -675,6 +675,12 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { unsafe { assert_eq!(size as usize as u64, size); if src.alloc_id == dest.alloc_id { + if nonoverlapping { + if (src.offset <= dest.offset && src.offset + size > dest.offset) || + (dest.offset <= src.offset && dest.offset + size > src.offset) { + return Err(EvalError::Intrinsic(format!("copy_nonoverlapping called on overlapping ranges"))); + } + } ptr::copy(src_bytes, dest_bytes, size as usize); } else { ptr::copy_nonoverlapping(src_bytes, dest_bytes, size as usize); diff --git a/src/terminator/intrinsic.rs b/src/terminator/intrinsic.rs index ae2d0b4f5dea..058936fd0445 100644 --- a/src/terminator/intrinsic.rs +++ b/src/terminator/intrinsic.rs @@ -140,7 +140,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { "copy" | "copy_nonoverlapping" => { - // FIXME: check whether overlapping occurs let elem_ty = substs.type_at(0); let elem_size = self.type_size(elem_ty)?.expect("cannot copy unsized value"); if elem_size != 0 { @@ -148,7 +147,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let src = arg_vals[0].read_ptr(&self.memory)?; let dest = arg_vals[1].read_ptr(&self.memory)?; let count = self.value_to_primval(arg_vals[2], usize)?.to_u64()?; - self.memory.copy(src, dest, count * elem_size, elem_align)?; + self.memory.copy(src, dest, count * elem_size, elem_align, intrinsic_name.ends_with("_nonoverlapping"))?; } } @@ -408,12 +407,20 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } "unchecked_shl" => { - // FIXME Check for too-wide shifts + let bits = self.type_size(dest_ty)?.expect("intrinsic can't be called on unsized type") as u128 * 8; + let rhs = self.value_to_primval(arg_vals[1], substs.type_at(0))?.to_bytes()?; + if rhs >= bits { + return Err(EvalError::Intrinsic(format!("Overflowing shift by {} in unchecked_shl", rhs))); + } self.intrinsic_overflowing(mir::BinOp::Shl, &args[0], &args[1], dest, dest_ty)?; } "unchecked_shr" => { - // FIXME Check for too-wide shifts + let bits = self.type_size(dest_ty)?.expect("intrinsic can't be called on unsized type") as u128 * 8; + let rhs = self.value_to_primval(arg_vals[1], substs.type_at(0))?.to_bytes()?; + if rhs >= bits { + return Err(EvalError::Intrinsic(format!("Overflowing shift by {} in unchecked_shr", rhs))); + } self.intrinsic_overflowing(mir::BinOp::Shr, &args[0], &args[1], dest, dest_ty)?; } diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail/copy_nonoverlapping.rs new file mode 100644 index 000000000000..f4acbadfd549 --- /dev/null +++ b/tests/compile-fail/copy_nonoverlapping.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +//error-pattern: copy_nonoverlapping called on overlapping ranges + +fn main() { + let mut data = [0u8; 16]; + unsafe { + let a = &data[0] as *const _; + let b = &mut data[1] as *mut _; + std::ptr::copy_nonoverlapping(a, b, 2); + } +} diff --git a/tests/compile-fail/div-by-zero.rs b/tests/compile-fail/div-by-zero.rs new file mode 100644 index 000000000000..4ac6214d88ab --- /dev/null +++ b/tests/compile-fail/div-by-zero.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +//error-pattern: Division by 0 in unchecked_div + +fn main() { + unsafe { + let _n = unchecked_div(1i64, 0); + } +} diff --git a/tests/compile-fail/overflowing-unchecked-rsh.rs b/tests/compile-fail/overflowing-unchecked-rsh.rs new file mode 100644 index 000000000000..b8291e1300ed --- /dev/null +++ b/tests/compile-fail/overflowing-unchecked-rsh.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +//error-pattern: Overflowing shift by 64 in unchecked_shr + +fn main() { + unsafe { + let _n = unchecked_shr(1i64, 64); + } +}