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 #425

Merged
merged 12 commits into from
Aug 14, 2018
5 changes: 3 additions & 2 deletions src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_metadata;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
Expand All @@ -12,7 +13,7 @@ extern crate syntax;
extern crate log;

use rustc::session::Session;
use rustc::middle::cstore::CrateStore;
use rustc_metadata::cstore::CStore;
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
Expand Down Expand Up @@ -70,7 +71,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
codegen_backend: &CodegenBackend,
matches: &getopts::Matches,
sess: &Session,
cstore: &CrateStore,
cstore: &CStore,
input: &Input,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>,
Expand Down
142 changes: 76 additions & 66 deletions src/fn_call.rs

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
// FIXME: assuming here that type size is < i64::max_value()
let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64;
let offset = offset.overflowing_mul(pointee_size).0;
ptr.ptr_wrapping_signed_offset(offset, self)
Ok(ptr.ptr_wrapping_signed_offset(offset, self))
}

fn pointer_offset(
Expand All @@ -65,7 +65,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
// We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own
// allocation.

if ptr.is_null()? {
if ptr.is_null() {
// NULL pointers must only be offset by 0
return if offset == 0 {
Ok(ptr)
Expand All @@ -80,7 +80,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
// Do not do bounds-checking for integers; they can never alias a normal pointer anyway.
if let Scalar::Ptr(ptr) = ptr {
self.memory.check_bounds(ptr, false)?;
} else if ptr.is_null()? {
} else if ptr.is_null() {
// We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now.
return err!(InvalidNullPointerUsage);
}
Expand All @@ -96,7 +96,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
) -> EvalResult<'tcx, i64> {
assert_eq!(value.ty, self.tcx.types.isize);
let raw = self.value_to_scalar(value)?.to_bits(self.memory.pointer_size())?;
let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.isize)?;
let raw = sign_extend(raw, self.layout_of(self.tcx.types.isize).unwrap());
Ok(raw as i64)
}

Expand All @@ -114,7 +114,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
) -> EvalResult<'tcx, i32> {
assert_eq!(value.ty, self.tcx.types.i32);
let raw = self.value_to_scalar(value)?.to_bits(Size::from_bits(32))?;
let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.i32)?;
let raw = sign_extend(raw, self.layout_of(self.tcx.types.i32).unwrap());
Ok(raw as i32)
}

Expand Down
150 changes: 72 additions & 78 deletions src/intrinsic.rs

Large diffs are not rendered by default.

77 changes: 32 additions & 45 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,53 +56,43 @@ use range_map::RangeMap;
use validation::{ValidationQuery, AbsPlace};

pub trait ScalarExt {
fn null() -> Self;
fn null(size: Size) -> Self;
fn from_i32(i: i32) -> Self;
fn from_u128(i: u128) -> Self;
fn from_i128(i: i128) -> Self;
fn from_usize(i: u64, ptr_size: Size) -> Self;
fn from_isize(i: i64, ptr_size: Size) -> Self;
fn from_uint(i: impl Into<u128>, ptr_size: Size) -> Self;
fn from_int(i: impl Into<i128>, ptr_size: Size) -> Self;
fn from_f32(f: f32) -> Self;
fn from_f64(f: f64) -> Self;
fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64>;
fn is_null(self) -> EvalResult<'static, bool>;
fn is_null(self) -> bool;
/// HACK: this function just extracts all bits if `defined != 0`
/// Mainly used for args of C-functions and we should totally correctly fetch the size
/// of their arguments
fn to_bytes(self) -> EvalResult<'static, u128>;
}

impl ScalarExt for Scalar {
fn null() -> Self {
Scalar::Bits { bits: 0, defined: 128 }
fn null(size: Size) -> Self {
Scalar::Bits { bits: 0, size: size.bytes() as u8 }
}

fn from_i32(i: i32) -> Self {
Scalar::Bits { bits: i as u32 as u128, defined: 32 }
Scalar::Bits { bits: i as u32 as u128, size: 4 }
}

fn from_u128(i: u128) -> Self {
Scalar::Bits { bits: i, defined: 128 }
fn from_uint(i: impl Into<u128>, ptr_size: Size) -> Self {
Scalar::Bits { bits: i.into(), size: ptr_size.bytes() as u8 }
}

fn from_i128(i: i128) -> Self {
Scalar::Bits { bits: i as u128, defined: 128 }
}

fn from_usize(i: u64, ptr_size: Size) -> Self {
Scalar::Bits { bits: i as u128, defined: ptr_size.bits() as u8 }
}

fn from_isize(i: i64, ptr_size: Size) -> Self {
Scalar::Bits { bits: i as i128 as u128, defined: ptr_size.bits() as u8 }
fn from_int(i: impl Into<i128>, ptr_size: Size) -> Self {
Scalar::Bits { bits: i.into() as u128, size: ptr_size.bytes() as u8 }
}

fn from_f32(f: f32) -> Self {
Scalar::Bits { bits: f.to_bits() as u128, defined: 32 }
Scalar::Bits { bits: f.to_bits() as u128, size: 4 }
}

fn from_f64(f: f64) -> Self {
Scalar::Bits { bits: f.to_bits() as u128, defined: 64 }
Scalar::Bits { bits: f.to_bits() as u128, size: 8 }
}

fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64> {
Expand All @@ -111,23 +101,19 @@ impl ScalarExt for Scalar {
Ok(b as u64)
}

fn is_null(self) -> EvalResult<'static, bool> {
fn is_null(self) -> bool {
match self {
Scalar::Bits { bits, defined } => {
if defined > 0 {
Ok(bits == 0)
} else {
err!(ReadUndefBytes)
}
}
Scalar::Ptr(_) => Ok(false)
Scalar::Bits { bits, .. } => bits == 0,
Scalar::Ptr(_) => false
}
}

fn to_bytes(self) -> EvalResult<'static, u128> {
match self {
Scalar::Bits { defined: 0, .. } => err!(ReadUndefBytes),
Scalar::Bits { bits, .. } => Ok(bits),
Scalar::Bits { bits, size } => {
assert_ne!(size, 0);
Ok(bits)
},
Scalar::Ptr(_) => err!(ReadPointerAsBytes),
}
}
Expand Down Expand Up @@ -155,6 +141,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
.to_owned(),
));
}
let ptr_size = ecx.memory.pointer_size();

if let Some(start_id) = start_wrapper {
let main_ret_ty = ecx.tcx.fn_sig(main_id).output();
Expand Down Expand Up @@ -199,7 +186,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx));
ecx.write_value(
ValTy {
value: Value::Scalar(Scalar::Ptr(main_ptr)),
value: Value::Scalar(Scalar::Ptr(main_ptr).into()),
ty: main_ptr_ty,
},
dest,
Expand All @@ -208,17 +195,16 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
// Second argument (argc): 1
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
let ty = ecx.tcx.types.isize;
ecx.write_scalar(dest, Scalar::from_u128(1), ty)?;
ecx.write_scalar(dest, Scalar::from_int(1, ptr_size), ty)?;

// FIXME: extract main source file path
// Third argument (argv): &[b"foo"]
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8));
let foo = ecx.memory.allocate_bytes(b"foo\0");
let ptr_size = ecx.memory.pointer_size();
let ptr_align = ecx.tcx.data_layout.pointer_align;
let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, MemoryKind::Stack)?;
ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?;
ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo).into(), ptr_size, ptr_align, false)?;
ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?;
ecx.write_ptr(dest, foo_ptr.into(), ty)?;

Expand All @@ -228,7 +214,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
main_instance,
main_mir.span,
main_mir,
Place::from_scalar_ptr(Scalar::from_u128(1), ty::layout::Align::from_bytes(1, 1).unwrap()),
Place::from_scalar_ptr(Scalar::from_int(1, ptr_size).into(), ty::layout::Align::from_bytes(1, 1).unwrap()),
StackPopCleanup::None,
)?;

Expand Down Expand Up @@ -294,7 +280,7 @@ pub fn eval_main<'a, 'tcx: 'a>(
trace!("Frame {}", i);
trace!(" return: {:#?}", frame.return_place);
for (i, local) in frame.locals.iter().enumerate() {
if let Some(local) = local {
if let Ok(local) = local.access() {
trace!(" local {}: {:?}", i, local);
}
}
Expand Down Expand Up @@ -519,15 +505,16 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> {

let mut args = ecx.frame().mir.args_iter();
let usize = ecx.tcx.types.usize;
let ptr_size = ecx.memory.pointer_size();

// First argument: size
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
ecx.write_value(
ValTy {
value: Value::Scalar(Scalar::from_u128(match layout.size.bytes() {
0 => 1 as u128,
size => size as u128,
})),
value: Value::Scalar(Scalar::from_uint(match layout.size.bytes() {
0 => 1,
size => size,
}, ptr_size).into()),
ty: usize,
},
dest,
Expand All @@ -537,7 +524,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> {
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
ecx.write_value(
ValTy {
value: Value::Scalar(Scalar::from_u128(layout.align.abi().into())),
value: Value::Scalar(Scalar::from_uint(layout.align.abi(), ptr_size).into()),
ty: usize,
},
dest,
Expand Down
7 changes: 4 additions & 3 deletions src/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
Sub => {
return self.binary_op(
Sub,
Scalar::Bits { bits: left.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 },
Scalar::Bits { bits: left.offset.bytes() as u128, size: self.memory.pointer_size().bytes() as u8 },
self.tcx.types.usize,
Scalar::Bits { bits: right.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 },
Scalar::Bits { bits: right.offset.bytes() as u128, size: self.memory.pointer_size().bytes() as u8 },
self.tcx.types.usize,
).map(Some)
}
Expand Down Expand Up @@ -182,12 +182,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
BitAnd if !signed => {
let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1);
let right = right as u64;
let ptr_size = self.memory.pointer_size().bytes() as u8;
if right & base_mask == base_mask {
// Case 1: The base address bits are all preserved, i.e., right is all-1 there
(Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false)
} else if right & base_mask == 0 {
// Case 2: The base address bits are all taken away, i.e., right is all-0 there
(Scalar::Bits { bits: (left.offset.bytes() & right) as u128, defined: 128 }, false)
(Scalar::Bits { bits: (left.offset.bytes() & right) as u128, size: ptr_size }, false)
} else {
return err!(ReadPointerAsBytes);
}
Expand Down
22 changes: 12 additions & 10 deletions src/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub trait MemoryExt<'tcx> {
fn fetch_tls_dtor(
&mut self,
key: Option<TlsKey>,
) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>>;
) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)>;
}

pub trait EvalContextExt<'tcx> {
Expand All @@ -22,10 +22,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu
fn create_tls_key(&mut self, dtor: Option<ty::Instance<'tcx>>) -> TlsKey {
let new_key = self.data.next_thread_local;
self.data.next_thread_local += 1;
let ptr_size = self.pointer_size();
self.data.thread_local.insert(
new_key,
TlsEntry {
data: Scalar::null(),
data: Scalar::null(ptr_size).into(),
dtor,
},
);
Expand Down Expand Up @@ -85,9 +86,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu
fn fetch_tls_dtor(
&mut self,
key: Option<TlsKey>,
) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>> {
) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> {
use std::collections::Bound::*;

let ptr_size = self.pointer_size();
let thread_local = &mut self.data.thread_local;
let start = match key {
Some(key) => Excluded(key),
Expand All @@ -96,21 +98,21 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu
for (&key, &mut TlsEntry { ref mut data, dtor }) in
thread_local.range_mut((start, Unbounded))
{
if !data.is_null()? {
if !data.is_null() {
if let Some(dtor) = dtor {
let ret = Some((dtor, *data, key));
*data = Scalar::null();
return Ok(ret);
*data = Scalar::null(ptr_size);
return ret;
}
}
}
Ok(None)
None
}
}

impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>> {
fn run_tls_dtors(&mut self) -> EvalResult<'tcx> {
let mut dtor = self.memory.fetch_tls_dtor(None)?;
let mut dtor = self.memory.fetch_tls_dtor(None);
// FIXME: replace loop by some structure that works with stepping
while let Some((instance, ptr, key)) = dtor {
trace!("Running TLS dtor {:?} on {:?}", instance, ptr);
Expand All @@ -134,9 +136,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
// step until out of stackframes
while self.step()? {}

dtor = match self.memory.fetch_tls_dtor(Some(key))? {
dtor = match self.memory.fetch_tls_dtor(Some(key)) {
dtor @ Some(_) => dtor,
None => self.memory.fetch_tls_dtor(None)?,
None => self.memory.fetch_tls_dtor(None),
};
}
// FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`.
Expand Down
8 changes: 4 additions & 4 deletions src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
Deref => Deref,
Field(f, _) => Field(f, ()),
Index(v) => {
let value = self.frame().get_local(v)?;
let value = self.frame().locals[v].access()?;
let ty = self.tcx.tcx.types.usize;
let n = self.value_to_scalar(ValTy { value, ty })?.to_usize(self)?;
Index(n)
Expand Down Expand Up @@ -480,7 +480,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
) -> EvalResult<'tcx> {
// Check alignment and non-NULLness
let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?;
let ptr = self.into_ptr(val)?;
let ptr = self.into_ptr(val)?.unwrap_or_err()?;
self.memory.check_align(ptr, align)?;

// Recurse
Expand Down Expand Up @@ -562,7 +562,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
};
// Handle locking
if len > 0 {
let ptr = ptr.to_ptr()?;
let ptr = ptr.unwrap_or_err()?.to_ptr()?;
match query.mutbl {
MutImmutable => {
if mode.acquiring() {
Expand Down Expand Up @@ -651,7 +651,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
}
TyFnPtr(_sig) => {
let ptr = self.read_place(query.place.1)?;
let ptr = self.into_ptr(ptr)?.to_ptr()?;
let ptr = self.into_ptr(ptr)?.unwrap_or_err()?.to_ptr()?;
self.memory.get_fn(ptr)?;
// TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
}
Expand Down