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

Rustup: Stacked Borrows #487

Merged
merged 13 commits into from
Oct 22, 2018
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
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nightly-2018-10-14
nightly-2018-10-22
97 changes: 51 additions & 46 deletions src/fn_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ pub trait EvalContextExt<'tcx, 'mir> {
fn emulate_foreign_item(
&mut self,
def_id: DefId,
args: &[OpTy<'tcx>],
dest: PlaceTy<'tcx>,
args: &[OpTy<'tcx, Borrow>],
dest: PlaceTy<'tcx, Borrow>,
ret: mir::BasicBlock,
) -> EvalResult<'tcx>;

Expand All @@ -24,28 +24,28 @@ pub trait EvalContextExt<'tcx, 'mir> {
fn emulate_missing_fn(
&mut self,
path: String,
args: &[OpTy<'tcx>],
dest: Option<PlaceTy<'tcx>>,
args: &[OpTy<'tcx, Borrow>],
dest: Option<PlaceTy<'tcx, Borrow>>,
ret: Option<mir::BasicBlock>,
) -> EvalResult<'tcx>;

fn find_fn(
&mut self,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx>],
dest: Option<PlaceTy<'tcx>>,
args: &[OpTy<'tcx, Borrow>],
dest: Option<PlaceTy<'tcx, Borrow>>,
ret: Option<mir::BasicBlock>,
) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>;

fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx>;
fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx>;
}

impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalContext<'a, 'mir, 'tcx> {
fn find_fn(
&mut self,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx>],
dest: Option<PlaceTy<'tcx>>,
args: &[OpTy<'tcx, Borrow>],
dest: Option<PlaceTy<'tcx, Borrow>>,
ret: Option<mir::BasicBlock>,
) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> {
trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place));
Expand Down Expand Up @@ -104,8 +104,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
fn emulate_foreign_item(
&mut self,
def_id: DefId,
args: &[OpTy<'tcx>],
dest: PlaceTy<'tcx>,
args: &[OpTy<'tcx, Borrow>],
dest: PlaceTy<'tcx, Borrow>,
ret: mir::BasicBlock,
) -> EvalResult<'tcx> {
let attrs = self.tcx.get_attrs(def_id);
Expand All @@ -114,6 +114,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
None => self.tcx.item_name(def_id).as_str(),
};

// All these functions take raw pointers, so if we access memory directly
// (as opposed to through a place), we have to remember to erase any tag
// that might still hang around!

match &link_name[..] {
"malloc" => {
let size = self.read_scalar(args[0])?.to_usize(&self)?;
Expand All @@ -127,10 +131,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
}

"free" => {
let ptr = self.read_scalar(args[0])?.not_undef()?;
let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation, no tag
if !ptr.is_null() {
self.memory.deallocate(
ptr.to_ptr()?,
ptr.to_ptr()?.with_default_tag(),
None,
MiriMemoryKind::C.into(),
)?;
Expand Down Expand Up @@ -167,7 +171,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
self.write_scalar(Scalar::Ptr(ptr), dest)?;
}
"__rust_dealloc" => {
let ptr = self.read_scalar(args[0])?.to_ptr()?;
let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag
let old_size = self.read_scalar(args[1])?.to_usize(&self)?;
let align = self.read_scalar(args[2])?.to_usize(&self)?;
if old_size == 0 {
Expand All @@ -177,13 +181,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
return err!(HeapAllocNonPowerOfTwoAlignment(align));
}
self.memory.deallocate(
ptr,
ptr.with_default_tag(),
Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())),
MiriMemoryKind::Rust.into(),
)?;
}
"__rust_realloc" => {
let ptr = self.read_scalar(args[0])?.to_ptr()?;
let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag
let old_size = self.read_scalar(args[1])?.to_usize(&self)?;
let align = self.read_scalar(args[2])?.to_usize(&self)?;
let new_size = self.read_scalar(args[3])?.to_usize(&self)?;
Expand All @@ -194,7 +198,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
return err!(HeapAllocNonPowerOfTwoAlignment(align));
}
let new_ptr = self.memory.reallocate(
ptr,
ptr.with_default_tag(),
Size::from_bytes(old_size),
Align::from_bytes(align, align).unwrap(),
Size::from_bytes(new_size),
Expand Down Expand Up @@ -226,8 +230,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '

"dlsym" => {
let _handle = self.read_scalar(args[0])?;
let symbol = self.read_scalar(args[1])?.to_ptr()?;
let symbol_name = self.memory.read_c_str(symbol)?;
let symbol = self.read_scalar(args[1])?.to_ptr()?.erase_tag();
let symbol_name = self.memory.read_c_str(symbol.with_default_tag())?;
let err = format!("bad c unicode symbol: {:?}", symbol_name);
let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
return err!(Unimplemented(format!(
Expand Down Expand Up @@ -280,13 +284,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
return err!(MachineError("the evaluated program panicked".to_string())),

"memcmp" => {
let left = self.read_scalar(args[0])?.not_undef()?;
let right = self.read_scalar(args[1])?.not_undef()?;
let left = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation
let right = self.read_scalar(args[1])?.not_undef()?.erase_tag(); // raw ptr operation
let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(&self)?);

let result = {
let left_bytes = self.memory.read_bytes(left, n)?;
let right_bytes = self.memory.read_bytes(right, n)?;
let left_bytes = self.memory.read_bytes(left.with_default_tag(), n)?;
let right_bytes = self.memory.read_bytes(right.with_default_tag(), n)?;

use std::cmp::Ordering::*;
match left_bytes.cmp(right_bytes) {
Expand All @@ -303,12 +307,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
}

"memrchr" => {
let ptr = self.read_scalar(args[0])?.not_undef()?;
let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation
let ptr = ptr.with_default_tag();
let val = self.read_scalar(args[1])?.to_bytes()? as u8;
let num = self.read_scalar(args[2])?.to_usize(&self)?;
if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position(
|&c| c == val,
)
if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?
.iter().rev().position(|&c| c == val)
{
let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?;
self.write_scalar(new_ptr, dest)?;
Expand All @@ -318,7 +322,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
}

"memchr" => {
let ptr = self.read_scalar(args[0])?.not_undef()?;
let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation
let ptr = ptr.with_default_tag();
let val = self.read_scalar(args[1])?.to_bytes()? as u8;
let num = self.read_scalar(args[2])?.to_usize(&self)?;
if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position(
Expand All @@ -334,8 +339,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '

"getenv" => {
let result = {
let name_ptr = self.read_scalar(args[0])?.to_ptr()?;
let name = self.memory.read_c_str(name_ptr)?;
let name_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation
let name = self.memory.read_c_str(name_ptr.with_default_tag())?;
match self.machine.env_vars.get(name) {
Some(&var) => Scalar::Ptr(var),
None => Scalar::ptr_null(*self.tcx),
Expand All @@ -347,9 +352,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
"unsetenv" => {
let mut success = None;
{
let name_ptr = self.read_scalar(args[0])?.not_undef()?;
let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation
if !name_ptr.is_null() {
let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?;
if !name.is_empty() && !name.contains(&b'=') {
success = Some(self.machine.env_vars.remove(name));
}
Expand All @@ -368,11 +373,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
"setenv" => {
let mut new = None;
{
let name_ptr = self.read_scalar(args[0])?.not_undef()?;
let value_ptr = self.read_scalar(args[1])?.to_ptr()?;
let value = self.memory.read_c_str(value_ptr)?;
let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation
let value_ptr = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); // raw ptr operation
let value = self.memory.read_c_str(value_ptr.with_default_tag())?;
if !name_ptr.is_null() {
let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?;
if !name.is_empty() && !name.contains(&b'=') {
new = Some((name.to_owned(), value.to_owned()));
}
Expand Down Expand Up @@ -403,14 +408,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '

"write" => {
let fd = self.read_scalar(args[0])?.to_bytes()?;
let buf = self.read_scalar(args[1])?.not_undef()?;
let buf = self.read_scalar(args[1])?.not_undef()?.erase_tag();
let n = self.read_scalar(args[2])?.to_bytes()? as u64;
trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
let result = if fd == 1 || fd == 2 {
// stdout/stderr
use std::io::{self, Write};

let buf_cont = self.memory.read_bytes(buf, Size::from_bytes(n))?;
let buf_cont = self.memory.read_bytes(buf.with_default_tag(), Size::from_bytes(n))?;
let res = if fd == 1 {
io::stdout().write(buf_cont)
} else {
Expand All @@ -431,8 +436,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
}

"strlen" => {
let ptr = self.read_scalar(args[0])?.to_ptr()?;
let n = self.memory.read_c_str(ptr)?.len();
let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag();
let n = self.memory.read_c_str(ptr.with_default_tag())?.len();
self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?;
}

Expand Down Expand Up @@ -478,7 +483,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '

// Hook pthread calls that go to the thread-local storage memory subsystem
"pthread_key_create" => {
let key_ptr = self.read_scalar(args[0])?.to_ptr()?;
let key_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation

// Extract the function type out of the signature (that seems easier than constructing it ourselves...)
let dtor = match self.read_scalar(args[1])?.not_undef()? {
Expand All @@ -501,7 +506,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
return err!(OutOfTls);
}
self.memory.write_scalar(
key_ptr,
key_ptr.with_default_tag(),
key_layout.align,
Scalar::from_uint(key, key_layout.size).into(),
key_layout.size,
Expand Down Expand Up @@ -637,8 +642,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
fn emulate_missing_fn(
&mut self,
path: String,
_args: &[OpTy<'tcx>],
dest: Option<PlaceTy<'tcx>>,
_args: &[OpTy<'tcx, Borrow>],
dest: Option<PlaceTy<'tcx, Borrow>>,
ret: Option<mir::BasicBlock>,
) -> EvalResult<'tcx> {
// In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early.
Expand Down Expand Up @@ -686,7 +691,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
Ok(())
}

fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx> {
fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> {
self.write_scalar(Scalar::from_int(0, dest.layout.size), dest)
}
}
4 changes: 2 additions & 2 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub trait ScalarExt {
fn to_bytes(self) -> EvalResult<'static, u128>;
}

impl ScalarExt for Scalar {
impl<Tag> ScalarExt for Scalar<Tag> {
fn to_bytes(self) -> EvalResult<'static, u128> {
match self {
Scalar::Bits { bits, size } => {
Expand All @@ -24,7 +24,7 @@ impl ScalarExt for Scalar {
}
}

impl ScalarExt for ScalarMaybeUndef {
impl<Tag> ScalarExt for ScalarMaybeUndef<Tag> {
fn to_bytes(self) -> EvalResult<'static, u128> {
self.not_undef()?.to_bytes()
}
Expand Down
28 changes: 16 additions & 12 deletions src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,38 @@ use rustc::ty::layout::{self, LayoutOf, Size};
use rustc::ty;

use rustc::mir::interpret::{EvalResult, PointerArithmetic};
use rustc_mir::interpret::{EvalContext, PlaceTy, OpTy};

use super::{
Value, Scalar, ScalarMaybeUndef,
PlaceTy, OpTy, Value, Scalar, ScalarMaybeUndef, Borrow,
ScalarExt, OperatorEvalContextExt
};

pub trait EvalContextExt<'tcx> {
fn call_intrinsic(
&mut self,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx>],
dest: PlaceTy<'tcx>,
args: &[OpTy<'tcx, Borrow>],
dest: PlaceTy<'tcx, Borrow>,
) -> EvalResult<'tcx>;
}

impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> {
fn call_intrinsic(
&mut self,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx>],
dest: PlaceTy<'tcx>,
args: &[OpTy<'tcx, Borrow>],
dest: PlaceTy<'tcx, Borrow>,
) -> EvalResult<'tcx> {
if self.emulate_intrinsic(instance, args, dest)? {
return Ok(());
}

let substs = instance.substs;

// All these intrinsics take raw pointers, so if we access memory directly
// (as opposed to through a place), we have to remember to erase any tag
// that might still hang around!

let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
match intrinsic_name {
"arith_offset" => {
Expand Down Expand Up @@ -147,12 +150,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
let elem_size = elem_layout.size.bytes();
let count = self.read_scalar(args[2])?.to_usize(&self)?;
let elem_align = elem_layout.align;
let src = self.read_scalar(args[0])?.not_undef()?;
let dest = self.read_scalar(args[1])?.not_undef()?;
// erase tags: this is a raw ptr operation
let src = self.read_scalar(args[0])?.not_undef()?.erase_tag();
let dest = self.read_scalar(args[1])?.not_undef()?.erase_tag();
self.memory.copy(
src,
src.with_default_tag(),
elem_align,
dest,
dest.with_default_tag(),
elem_align,
Size::from_bytes(count * elem_size),
intrinsic_name.ends_with("_nonoverlapping"),
Expand Down Expand Up @@ -429,7 +433,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
let ty = substs.type_at(0);
let ty_layout = self.layout_of(ty)?;
let val_byte = self.read_scalar(args[1])?.to_u8()?;
let ptr = self.read_scalar(args[0])?.not_undef()?;
let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag().with_default_tag();
let count = self.read_scalar(args[2])?.to_usize(&self)?;
self.memory.check_align(ptr, ty_layout.align)?;
self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?;
Expand Down
Loading