check the assumptions made by the unchecked_ and copy_nonoverlapping intrinsics

This commit is contained in:
Ralf Jung 2017-07-03 20:27:09 -07:00
parent f118ff43e7
commit ffd482e2f5
6 changed files with 85 additions and 6 deletions

View file

@ -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(())
}

View file

@ -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);

View file

@ -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)?;
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}
}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}
}