This commit is contained in:
Oliver Schneider 2018-08-07 15:22:11 +02:00
parent b784c81e8e
commit be91aea0fa
8 changed files with 206 additions and 213 deletions

View file

@ -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;
@ -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};
@ -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>,

View file

@ -37,7 +37,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>(
.val;
let (discr_dest, discr) = ecx.place_field(dest, mir::Field::new(0), layout)?;
ecx.write_scalar(discr_dest, Scalar::from_u128(discr_val), discr.ty)?;
ecx.write_scalar(discr_dest, Scalar::from_uint(discr_val, discr.size), discr.ty)?;
}
layout::Variants::NicheFilling {
dataful_variant,
@ -50,7 +50,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>(
ecx.place_field(dest, mir::Field::new(0), layout)?;
let niche_value = ((variant_index - niche_variants.start()) as u128)
.wrapping_add(niche_start);
ecx.write_scalar(niche_dest, Scalar::from_u128(niche_value), niche.ty)?;
ecx.write_scalar(niche_dest, Scalar::from_uint(niche_value, niche.size), niche.ty)?;
}
}
}
@ -88,7 +88,7 @@ pub trait EvalContextExt<'tcx> {
sig: ty::FnSig<'tcx>,
) -> EvalResult<'tcx, bool>;
fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>;
fn write_null(&mut self, dest: Place, dest_layout: TyLayout<'tcx>) -> EvalResult<'tcx>;
}
impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
@ -138,7 +138,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
let amt = 128 - self.memory.pointer_size().bytes() * 8;
let (dest, return_to_block) = destination.unwrap();
let ty = self.tcx.types.usize;
self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), ty)?;
let ptr_size = self.memory.pointer_size();
self.write_scalar(dest, Scalar::from_uint((n << amt) >> amt, ptr_size), ty)?;
self.goto_block(return_to_block);
return Ok(true);
}
@ -187,12 +188,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
Some(name) => name.as_str(),
None => self.tcx.item_name(def_id).as_str(),
};
let dest_layout = self.layout_of(dest_ty)?;
match &link_name[..] {
"malloc" => {
let size = self.value_to_scalar(args[0])?.to_usize(self)?;
if size == 0 {
self.write_null(dest, dest_ty)?;
self.write_null(dest, dest_layout)?;
} else {
let align = self.tcx.data_layout.pointer_align;
let ptr = self.memory.allocate(Size::from_bytes(size), align, MemoryKind::C.into())?;
@ -201,8 +203,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
}
"free" => {
let ptr = self.into_ptr(args[0].value)?;
if !ptr.is_null()? {
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
if !ptr.is_null() {
self.memory.deallocate(
ptr.to_ptr()?,
None,
@ -241,7 +243,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?;
}
"__rust_dealloc" => {
let ptr = self.into_ptr(args[0].value)?.to_ptr()?;
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?;
let old_size = self.value_to_scalar(args[1])?.to_usize(self)?;
let align = self.value_to_scalar(args[2])?.to_usize(self)?;
if old_size == 0 {
@ -257,7 +259,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
)?;
}
"__rust_realloc" => {
let ptr = self.into_ptr(args[0].value)?.to_ptr()?;
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?;
let old_size = self.value_to_scalar(args[1])?.to_usize(self)?;
let align = self.value_to_scalar(args[2])?.to_usize(self)?;
let new_size = self.value_to_scalar(args[3])?.to_usize(self)?;
@ -300,7 +302,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
"dlsym" => {
let _handle = self.into_ptr(args[0].value)?;
let symbol = self.into_ptr(args[1].value)?.to_ptr()?;
let symbol = self.into_ptr(args[1].value)?.unwrap_or_err()?.to_ptr()?;
let symbol_name = self.memory.read_c_str(symbol)?;
let err = format!("bad c unicode symbol: {:?}", symbol_name);
let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
@ -314,10 +316,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
// fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32
// We abort on panic, so not much is going on here, but we still have to call the closure
let u8_ptr_ty = self.tcx.mk_mut_ptr(self.tcx.types.u8);
let f = self.into_ptr(args[0].value)?.to_ptr()?;
let data = self.into_ptr(args[1].value)?;
let f = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?;
let data = self.into_ptr(args[1].value)?.unwrap_or_err()?;
let f_instance = self.memory.get_fn(f)?;
self.write_null(dest, dest_ty)?;
self.write_null(dest, dest_layout)?;
// Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors,
// and of course eval_main.
@ -343,7 +345,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected");
// We ourselves return 0
self.write_null(dest, dest_ty)?;
self.write_null(dest, dest_layout)?;
// Don't fall through
return Ok(());
@ -354,8 +356,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
}
"memcmp" => {
let left = self.into_ptr(args[0].value)?;
let right = self.into_ptr(args[1].value)?;
let left = self.into_ptr(args[0].value)?.unwrap_or_err()?;
let right = self.into_ptr(args[1].value)?.unwrap_or_err()?;
let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_usize(self)?);
let result = {
@ -378,7 +380,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
}
"memrchr" => {
let ptr = self.into_ptr(args[0].value)?;
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
let val = self.value_to_scalar(args[1])?.to_bytes()? as u8;
let num = self.value_to_scalar(args[2])?.to_usize(self)?;
if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position(
@ -388,12 +390,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?;
self.write_ptr(dest, new_ptr, dest_ty)?;
} else {
self.write_null(dest, dest_ty)?;
self.write_null(dest, dest_layout)?;
}
}
"memchr" => {
let ptr = self.into_ptr(args[0].value)?;
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
let val = self.value_to_scalar(args[1])?.to_bytes()? as u8;
let num = self.value_to_scalar(args[2])?.to_usize(self)?;
if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position(
@ -403,17 +405,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), &self)?;
self.write_ptr(dest, new_ptr, dest_ty)?;
} else {
self.write_null(dest, dest_ty)?;
self.write_null(dest, dest_layout)?;
}
}
"getenv" => {
let result = {
let name_ptr = self.into_ptr(args[0].value)?.to_ptr()?;
let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?;
let name = self.memory.read_c_str(name_ptr)?;
match self.machine.env_vars.get(name) {
Some(&var) => Scalar::Ptr(var),
None => Scalar::null(),
None => Scalar::null(self.memory.pointer_size()),
}
};
self.write_scalar(dest, result, dest_ty)?;
@ -422,8 +424,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
"unsetenv" => {
let mut success = None;
{
let name_ptr = self.into_ptr(args[0].value)?;
if !name_ptr.is_null()? {
let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
if !name_ptr.is_null() {
let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
if !name.is_empty() && !name.contains(&b'=') {
success = Some(self.machine.env_vars.remove(name));
@ -434,19 +436,19 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
if let Some(var) = old {
self.memory.deallocate(var, None, MemoryKind::Env.into())?;
}
self.write_null(dest, dest_ty)?;
self.write_null(dest, dest_layout)?;
} else {
self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?;
self.write_scalar(dest, Scalar::from_int(-1, dest_layout.size), dest_ty)?;
}
}
"setenv" => {
let mut new = None;
{
let name_ptr = self.into_ptr(args[0].value)?;
let value_ptr = self.into_ptr(args[1].value)?.to_ptr()?;
let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
let value_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?.to_ptr()?;
let value = self.memory.read_c_str(value_ptr)?;
if !name_ptr.is_null()? {
if !name_ptr.is_null() {
let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
if !name.is_empty() && !name.contains(&b'=') {
new = Some((name.to_owned(), value.to_owned()));
@ -470,15 +472,15 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
{
self.memory.deallocate(var, None, MemoryKind::Env.into())?;
}
self.write_null(dest, dest_ty)?;
self.write_null(dest, dest_layout)?;
} else {
self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?;
self.write_scalar(dest, Scalar::from_int(-1, dest_layout.size), dest_ty)?;
}
}
"write" => {
let fd = self.value_to_scalar(args[0])?.to_bytes()?;
let buf = self.into_ptr(args[1].value)?;
let buf = self.into_ptr(args[1].value)?.unwrap_or_err()?;
let n = self.value_to_scalar(args[2])?.to_bytes()? as u64;
trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
let result = if fd == 1 || fd == 2 {
@ -502,31 +504,33 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
let ptr_size = self.memory.pointer_size();
self.write_scalar(
dest,
Scalar::from_isize(result, ptr_size),
Scalar::from_int(result, ptr_size),
dest_ty,
)?;
}
"strlen" => {
let ptr = self.into_ptr(args[0].value)?.to_ptr()?;
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?;
let n = self.memory.read_c_str(ptr)?.len();
let ptr_size = self.memory.pointer_size();
self.write_scalar(dest, Scalar::from_usize(n as u64, ptr_size), dest_ty)?;
self.write_scalar(dest, Scalar::from_uint(n as u64, ptr_size), dest_ty)?;
}
// Some things needed for sys::thread initialization to go through
"signal" | "sigaction" | "sigaltstack" => {
self.write_scalar(dest, Scalar::null(), dest_ty)?;
let ptr_size = self.memory.pointer_size();
self.write_scalar(dest, Scalar::null(ptr_size), dest_ty)?;
}
"sysconf" => {
let name = self.value_to_scalar(args[0])?.to_usize(self)?;
let ptr_size = self.memory.pointer_size();
trace!("sysconf() called with name {}", name);
// cache the sysconf integers via miri's global cache
let paths = &[
(&["libc", "_SC_PAGESIZE"], Scalar::from_i128(4096)),
(&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_i128(-1)),
(&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, ptr_size)),
(&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, ptr_size)),
];
let mut result = None;
for &(path, path_value) in paths {
@ -554,43 +558,45 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
// Hook pthread calls that go to the thread-local storage memory subsystem
"pthread_key_create" => {
let key_ptr = self.into_ptr(args[0].value)?;
let key_align = self.layout_of(args[0].ty)?.align;
let key_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
// Extract the function type out of the signature (that seems easier than constructing it ourselves...)
let dtor = match self.into_ptr(args[1].value)? {
let dtor = match self.into_ptr(args[1].value)?.unwrap_or_err()? {
Scalar::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?),
Scalar::Bits { defined: 0, .. } => return err!(ReadUndefBytes),
Scalar::Bits { bits: 0, .. } => None,
Scalar::Bits { bits: 0, size } => {
assert_eq!(size as u64, self.memory.pointer_size().bytes());
None
},
Scalar::Bits { .. } => return err!(ReadBytesAsPointer),
};
// Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t.
let key_type = args[0].ty.builtin_deref(true)
.ok_or_else(|| EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty;
let key_size = self.layout_of(key_type)?.size;
let key_layout = self.layout_of(key_type)?;
// Create key and write it into the memory where key_ptr wants it
let key = self.memory.create_tls_key(dtor) as u128;
if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) {
if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) {
return err!(OutOfTls);
}
self.memory.write_scalar(
key_ptr,
key_align,
Scalar::from_u128(key),
key_size,
key_layout.align,
Scalar::from_uint(key, key_layout.size).into(),
key_layout.size,
key_layout.align,
false,
)?;
// Return success (0)
self.write_null(dest, dest_ty)?;
self.write_null(dest, dest_layout)?;
}
"pthread_key_delete" => {
let key = self.value_to_scalar(args[0])?.to_bytes()?;
self.memory.delete_tls_key(key)?;
// Return success (0)
self.write_null(dest, dest_ty)?;
self.write_null(dest, dest_layout)?;
}
"pthread_getspecific" => {
let key = self.value_to_scalar(args[0])?.to_bytes()?;
@ -599,11 +605,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
}
"pthread_setspecific" => {
let key = self.value_to_scalar(args[0])?.to_bytes()?;
let new_ptr = self.into_ptr(args[1].value)?;
let new_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?;
self.memory.store_tls(key, new_ptr)?;
// Return success (0)
self.write_null(dest, dest_ty)?;
self.write_null(dest, dest_layout)?;
}
"_tlv_atexit" => {
@ -613,19 +619,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
// Stub out all the other pthread calls to just return 0
link_name if link_name.starts_with("pthread_") => {
debug!("ignoring C ABI call: {}", link_name);
self.write_null(dest, dest_ty)?;
self.write_null(dest, dest_layout)?;
}
"mmap" => {
// This is a horrible hack, but well... the guard page mechanism calls mmap and expects a particular return value, so we give it that value
let addr = self.into_ptr(args[0].value)?;
let addr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
self.write_ptr(dest, addr, dest_ty)?;
}
// Windows API subs
"AddVectoredExceptionHandler" => {
// any non zero value works for the stdlib. This is just used for stackoverflows anyway
self.write_scalar(dest, Scalar::from_u128(1), dest_ty)?;
let ptr_size = self.memory.pointer_size();
self.write_scalar(dest, Scalar::from_int(1, ptr_size), dest_ty)?;
},
"GetModuleHandleW" |
"GetProcAddress" |
@ -636,26 +643,28 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
"DeleteCriticalSection" |
"SetLastError" => {
// pretend these do not exist/nothing happened, by returning zero
self.write_scalar(dest, Scalar::from_u128(0), dest_ty)?;
let ptr_size = self.memory.pointer_size();
self.write_scalar(dest, Scalar::from_int(0, ptr_size), dest_ty)?;
},
"GetLastError" => {
// this is c::ERROR_CALL_NOT_IMPLEMENTED
self.write_scalar(dest, Scalar::from_u128(120), dest_ty)?;
let ptr_size = self.memory.pointer_size();
self.write_scalar(dest, Scalar::from_int(120, ptr_size), dest_ty)?;
},
// Windows TLS
"TlsAlloc" => {
// This just creates a key; Windows does not natively support TLS dtors.
// Figure out how large a TLS key actually is. This is c::DWORD.
let key_size = self.layout_of(dest_ty)?.size;
// Create key and return it
let key = self.memory.create_tls_key(None) as u128;
if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) {
// Figure out how large a TLS key actually is. This is c::DWORD.
if dest_layout.size.bits() < 128 && key >= (1u128 << dest_layout.size.bits() as u128) {
return err!(OutOfTls);
}
self.write_scalar(dest, Scalar::from_u128(key), dest_ty)?;
let ptr_size = self.memory.pointer_size();
self.write_scalar(dest, Scalar::from_uint(key, ptr_size), dest_layout.ty)?;
}
"TlsGetValue" => {
let key = self.value_to_scalar(args[0])?.to_bytes()?;
@ -664,11 +673,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
}
"TlsSetValue" => {
let key = self.value_to_scalar(args[0])?.to_bytes()?;
let new_ptr = self.into_ptr(args[1].value)?;
let new_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?;
self.memory.store_tls(key, new_ptr)?;
let ptr_size = self.memory.pointer_size();
// Return success (1)
self.write_scalar(dest, Scalar::from_u128(1), dest_ty)?;
self.write_scalar(dest, Scalar::from_int(1, ptr_size), dest_ty)?;
}
// We can't execute anything else
@ -791,7 +801,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
Ok(())
}
fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> {
self.write_scalar(dest, Scalar::null(), dest_ty)
fn write_null(&mut self, dest: Place, dest_layout: TyLayout<'tcx>) -> EvalResult<'tcx> {
self.write_scalar(dest, Scalar::null(dest_layout.size), dest_layout.ty)
}
}

View file

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

View file

@ -2,7 +2,7 @@ use rustc::mir;
use rustc::ty::layout::{TyLayout, LayoutOf, Size, Primitive, Integer::*};
use rustc::ty;
use rustc::mir::interpret::{EvalResult, Scalar, Value};
use rustc::mir::interpret::{EvalResult, Scalar, Value, ScalarMaybeUndef};
use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy};
use helpers::EvalContextExt as HelperEvalContextExt;
@ -65,7 +65,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
"arith_offset" => {
let offset = self.value_to_isize(args[1])?;
let ptr = self.into_ptr(args[0].value)?;
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?;
self.write_ptr(dest, result_ptr, dest_layout.ty)?;
}
@ -81,7 +81,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
"atomic_load_relaxed" |
"atomic_load_acq" |
"volatile_load" => {
let ptr = self.into_ptr(args[0].value)?;
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
let align = self.layout_of(args[0].ty)?.align;
let valty = ValTy {
@ -97,7 +97,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
"volatile_store" => {
let ty = substs.type_at(0);
let align = self.layout_of(ty)?.align;
let dest = self.into_ptr(args[0].value)?;
let dest = self.into_ptr(args[0].value)?.unwrap_or_err()?;
self.write_value_to_ptr(args[1].value, dest, align, ty)?;
}
@ -108,7 +108,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
_ if intrinsic_name.starts_with("atomic_xchg") => {
let ty = substs.type_at(0);
let align = self.layout_of(ty)?.align;
let ptr = self.into_ptr(args[0].value)?;
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
let change = self.value_to_scalar(args[1])?;
let old = self.read_value(ptr, align, ty)?;
let old = match old {
@ -118,7 +118,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
};
self.write_scalar(dest, old, ty)?;
self.write_scalar(
Place::from_scalar_ptr(ptr, align),
Place::from_scalar_ptr(ptr.into(), align),
change,
ty,
)?;
@ -127,23 +127,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
_ if intrinsic_name.starts_with("atomic_cxchg") => {
let ty = substs.type_at(0);
let align = self.layout_of(ty)?.align;
let ptr = self.into_ptr(args[0].value)?;
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
let expect_old = self.value_to_scalar(args[1])?;
let change = self.value_to_scalar(args[2])?;
let old = self.read_value(ptr, align, ty)?;
let old = match old {
Value::Scalar(val) => val,
Value::Scalar(val) => val.unwrap_or_err()?,
Value::ByRef { .. } => bug!("just read the value, can't be byref"),
Value::ScalarPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"),
};
let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?;
let valty = ValTy {
value: Value::ScalarPair(old, val),
value: Value::ScalarPair(old.into(), val.into()),
ty: dest_layout.ty,
};
self.write_value(valty, dest)?;
self.write_scalar(
Place::from_scalar_ptr(ptr, dest_layout.align),
Place::from_scalar_ptr(ptr.into(), dest_layout.align),
change,
ty,
)?;
@ -176,7 +176,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
"atomic_xsub_relaxed" => {
let ty = substs.type_at(0);
let align = self.layout_of(ty)?.align;
let ptr = self.into_ptr(args[0].value)?;
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
let change = self.value_to_scalar(args[1])?;
let old = self.read_value(ptr, align, ty)?;
let old = match old {
@ -196,8 +196,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
_ => bug!(),
};
// FIXME: what do atomics do on overflow?
let (val, _) = self.binary_op(op, old, ty, change, ty)?;
self.write_scalar(Place::from_scalar_ptr(ptr, dest_layout.align), val, ty)?;
let (val, _) = self.binary_op(op, old.unwrap_or_err()?, ty, change, ty)?;
self.write_scalar(Place::from_scalar_ptr(ptr.into(), dest_layout.align), val, ty)?;
}
"breakpoint" => unimplemented!(), // halt miri
@ -212,8 +212,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
// TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next.
// Also see the write_bytes intrinsic.
let elem_align = elem_layout.align;
let src = self.into_ptr(args[0].value)?;
let dest = self.into_ptr(args[1].value)?;
let src = self.into_ptr(args[0].value)?.unwrap_or_err()?;
let dest = self.into_ptr(args[1].value)?.unwrap_or_err()?;
self.memory.copy(
src,
elem_align,
@ -250,7 +250,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
let adt_align = self.layout_of(args[0].ty)?.align;
let place = Place::from_scalar_ptr(adt_ptr, adt_align);
let discr_val = self.read_discriminant_value(place, layout)?;
self.write_scalar(dest, Scalar::from_u128(discr_val), dest_layout.ty)?;
let ptr_size = self.memory.pointer_size();
self.write_scalar(dest, Scalar::from_uint(discr_val, ptr_size), dest_layout.ty)?;
}
"sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" |
@ -320,7 +321,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
let a = self.value_to_scalar(args[0])?;
let b = self.value_to_scalar(args[1])?;
// check x % y != 0
if !self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0.is_null()? {
if !self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0.is_null() {
return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b)));
}
let result = self.binary_op(mir::BinOp::Div, a, ty, b, ty)?;
@ -330,41 +331,24 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
"likely" | "unlikely" | "forget" => {}
"init" => {
let size = dest_layout.size;
let init = |this: &mut Self, val: Value| {
let zero_val = match val {
Value::ByRef(ptr, _) => {
// These writes have no alignment restriction anyway.
this.memory.write_repeat(ptr, 0, size)?;
val
}
// TODO(solson): Revisit this, it's fishy to check for Undef here.
Value::Scalar(Scalar::Bits { defined: 0, .. }) => {
match this.layout_of(dest_layout.ty)?.abi {
ty::layout::Abi::Scalar(_) => Value::Scalar(Scalar::null()),
_ => {
// FIXME(oli-obk): pass TyLayout to alloc_ptr instead of Ty
let ptr = this.alloc_ptr(dest_layout)?;
let ptr = Scalar::Ptr(ptr);
this.memory.write_repeat(ptr, 0, size)?;
Value::ByRef(ptr, dest_layout.align)
}
match dest {
Place::Local { frame, local } => {
match self.stack()[frame].locals[local].access()? {
Value::ByRef(ptr, _) => {
// These writes have no alignment restriction anyway.
self.memory.write_repeat(ptr, 0, dest_layout.size)?;
}
Value::Scalar(_) => self.write_value(ValTy { value: Value::Scalar(Scalar::null(dest_layout.size).into()), ty: dest_layout.ty }, dest)?,
Value::ScalarPair(..) => {
self.write_value(ValTy { value: Value::ScalarPair(Scalar::null(dest_layout.size).into(), Scalar::null(dest_layout.size).into()), ty: dest_layout.ty }, dest)?;
}
}
Value::Scalar(_) => Value::Scalar(Scalar::null()),
Value::ScalarPair(..) => {
Value::ScalarPair(Scalar::null(), Scalar::null())
}
};
Ok(zero_val)
};
match dest {
Place::Local { frame, local } => self.modify_local(frame, local, init)?,
},
Place::Ptr {
ptr,
align: _align,
extra: PlaceExtra::None,
} => self.memory.write_repeat(ptr, 0, size)?,
} => self.memory.write_repeat(ptr.unwrap_or_err()?, 0, dest_layout.size)?,
Place::Ptr { .. } => {
bug!("init intrinsic tried to write to fat or unaligned ptr target")
}
@ -374,7 +358,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
"min_align_of" => {
let elem_ty = substs.type_at(0);
let elem_align = self.layout_of(elem_ty)?.align.abi();
let align_val = Scalar::from_u128(elem_align as u128);
let ptr_size = self.memory.pointer_size();
let align_val = Scalar::from_uint(elem_align as u128, ptr_size);
self.write_scalar(dest, align_val, dest_layout.ty)?;
}
@ -382,13 +367,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
let ty = substs.type_at(0);
let layout = self.layout_of(ty)?;
let align = layout.align.pref();
let align_val = Scalar::from_u128(align as u128);
let ptr_size = self.memory.pointer_size();
let align_val = Scalar::from_uint(align as u128, ptr_size);
self.write_scalar(dest, align_val, dest_layout.ty)?;
}
"move_val_init" => {
let ty = substs.type_at(0);
let ptr = self.into_ptr(args[0].value)?;
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
let align = self.layout_of(args[0].ty)?.align;
self.write_value_to_ptr(args[1].value, ptr, align, ty)?;
}
@ -406,7 +392,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
"offset" => {
let offset = self.value_to_isize(args[1])?;
let ptr = self.into_ptr(args[0].value)?;
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?;
self.write_ptr(dest, result_ptr, dest_layout.ty)?;
}
@ -517,16 +503,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
"size_of" => {
let ty = substs.type_at(0);
let size = self.layout_of(ty)?.size.bytes().into();
self.write_scalar(dest, Scalar::from_u128(size), dest_layout.ty)?;
let size = self.layout_of(ty)?.size.bytes();
let ptr_size = self.memory.pointer_size();
self.write_scalar(dest, Scalar::from_uint(size, ptr_size), dest_layout.ty)?;
}
"size_of_val" => {
let ty = substs.type_at(0);
let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?;
let ptr_size = self.memory.pointer_size();
self.write_scalar(
dest,
Scalar::from_u128(size.bytes() as u128),
Scalar::from_uint(size.bytes() as u128, ptr_size),
dest_layout.ty,
)?;
}
@ -535,9 +523,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
"align_of_val" => {
let ty = substs.type_at(0);
let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?;
let ptr_size = self.memory.pointer_size();
self.write_scalar(
dest,
Scalar::from_u128(align.abi() as u128),
Scalar::from_uint(align.abi(), ptr_size),
dest_layout.ty,
)?;
}
@ -551,7 +540,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
"type_id" => {
let ty = substs.type_at(0);
let n = self.tcx.type_id_hash(ty);
self.write_scalar(dest, Scalar::Bits { bits: n as u128, defined: 64 }, dest_layout.ty)?;
self.write_scalar(dest, Scalar::Bits { bits: n as u128, size: 8 }, dest_layout.ty)?;
}
"transmute" => {
@ -629,21 +618,24 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
}
"uninit" => {
let size = dest_layout.size;
let uninit = |this: &mut Self, val: Value| match val {
Value::ByRef(ptr, _) => {
this.memory.mark_definedness(ptr, size, false)?;
Ok(val)
}
_ => Ok(Value::Scalar(Scalar::undef())),
};
match dest {
Place::Local { frame, local } => self.modify_local(frame, local, uninit)?,
Place::Local { frame, local } => {
match self.stack()[frame].locals[local].access()? {
Value::ByRef(ptr, _) => {
// These writes have no alignment restriction anyway.
self.memory.mark_definedness(ptr, dest_layout.size, false)?;
}
Value::Scalar(_) => self.write_value(ValTy { value: Value::Scalar(ScalarMaybeUndef::Undef), ty: dest_layout.ty }, dest)?,
Value::ScalarPair(..) => {
self.write_value(ValTy { value: Value::ScalarPair(ScalarMaybeUndef::Undef, ScalarMaybeUndef::Undef), ty: dest_layout.ty }, dest)?;
}
}
},
Place::Ptr {
ptr,
align: _align,
extra: PlaceExtra::None,
} => self.memory.mark_definedness(ptr, size, false)?,
} => self.memory.mark_definedness(ptr.unwrap_or_err()?, dest_layout.size, false)?,
Place::Ptr { .. } => {
bug!("uninit intrinsic tried to write to fat or unaligned ptr target")
}
@ -654,7 +646,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.value_to_u8(args[1])?;
let ptr = self.into_ptr(args[0].value)?;
let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?;
let count = self.value_to_usize(args[2])?;
if count > 0 {
// HashMap relies on write_bytes on a NULL ptr with count == 0 to work
@ -683,21 +675,21 @@ fn numeric_intrinsic<'tcx>(
) -> EvalResult<'tcx, Scalar> {
macro_rules! integer_intrinsic {
($method:ident) => ({
let result_bytes = match kind {
Primitive::Int(I8, true) => (bytes as i8).$method() as u128,
Primitive::Int(I8, false) => (bytes as u8).$method() as u128,
Primitive::Int(I16, true) => (bytes as i16).$method() as u128,
Primitive::Int(I16, false) => (bytes as u16).$method() as u128,
Primitive::Int(I32, true) => (bytes as i32).$method() as u128,
Primitive::Int(I32, false) => (bytes as u32).$method() as u128,
Primitive::Int(I64, true) => (bytes as i64).$method() as u128,
Primitive::Int(I64, false) => (bytes as u64).$method() as u128,
Primitive::Int(I128, true) => (bytes as i128).$method() as u128,
Primitive::Int(I128, false) => bytes.$method() as u128,
let (result_bytes, size) = match kind {
Primitive::Int(I8, true) => ((bytes as i8).$method() as u128, 1),
Primitive::Int(I8, false) => ((bytes as u8).$method() as u128, 1),
Primitive::Int(I16, true) => ((bytes as i16).$method() as u128, 2),
Primitive::Int(I16, false) => ((bytes as u16).$method() as u128, 2),
Primitive::Int(I32, true) => ((bytes as i32).$method() as u128, 4),
Primitive::Int(I32, false) => ((bytes as u32).$method() as u128, 4),
Primitive::Int(I64, true) => ((bytes as i64).$method() as u128, 8),
Primitive::Int(I64, false) => ((bytes as u64).$method() as u128, 8),
Primitive::Int(I128, true) => ((bytes as i128).$method() as u128, 16),
Primitive::Int(I128, false) => (bytes.$method() as u128, 16),
_ => bug!("invalid `{}` argument: {:?}", name, bytes),
};
Scalar::from_u128(result_bytes)
Scalar::from_uint(result_bytes, Size::from_bytes(size))
});
}

View file

@ -56,16 +56,14 @@ 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
@ -73,36 +71,28 @@ pub trait ScalarExt {
}
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> {
@ -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),
}
}
@ -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();
@ -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,
@ -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)?;
@ -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,
)?;
@ -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);
}
}
@ -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,
@ -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,

View file

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

View file

@ -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> {
@ -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,
},
);
@ -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),
@ -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);
@ -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`.

View file

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