From 68378a7b9772a58c6b1035e998f7d4d6ee2a6725 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 May 2018 13:14:26 +0200 Subject: [PATCH 1/7] Rustup to rustc 1.27.0-nightly (ff2ac35db 2018-05-12) --- src/fn_call.rs | 2 +- src/validation.rs | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 2b4e7b7366..272c27e402 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -459,7 +459,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' promoted: None, }; let const_val = self.const_eval(cid)?; - let value = const_val.val.unwrap_u64(); + let value = const_val.unwrap_usize(self.tcx.tcx); if value == name { result = Some(path_value); break; diff --git a/src/validation.rs b/src/validation.rs index b274b46501..deb1c5d5bc 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -10,7 +10,7 @@ use rustc::infer::InferCtxt; use rustc::middle::region; use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; -use rustc_mir::interpret::{HasMemory, eval_body}; +use rustc_mir::interpret::HasMemory; use super::{EvalContext, Place, PlaceExtra, ValTy}; use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; @@ -718,18 +718,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } TyArray(elem_ty, len) => { - let len_val = match len.val { + let len = match len.val { ConstVal::Unevaluated(def_id, substs) => { - eval_body(self.tcx.tcx, GlobalId { + self.tcx.const_eval(self.tcx.param_env(def_id).and(GlobalId { instance: Instance::new(def_id, substs), promoted: None, - }, ty::ParamEnv::reveal_all()) - .ok_or_else(||EvalErrorKind::MachineError("".to_string()))? - .0 + })) + .map_err(|_err|EvalErrorKind::MachineError("".to_string()))? } - ConstVal::Value(val) => val, + ConstVal::Value(_) => len, }; - let len = ConstVal::Value(len_val).unwrap_u64(); + let len = len.unwrap_usize(self.tcx.tcx); for i in 0..len { let inner_place = self.place_index(query.place.1, query.ty, i as u64)?; self.validate( From 1bf0ffcb27ff8e38424f1e4115b52752cd0eeb70 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 May 2018 15:32:35 +0200 Subject: [PATCH 2/7] Enable backtraces for tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6a987f9374..9aa632da05 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ script: - | # Test plain miri cargo build --release --all-features && - cargo test --release --all-features --all && + RUST_BACKTRACE=1 cargo test --release --all-features --all && cargo install --all-features --force - | # Test cargo miri From d3b9085f1aec3cd60818e76fc2436145081cf7c6 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 19 May 2018 12:14:13 +0200 Subject: [PATCH 3/7] Rustup to rustc 1.28.0-nightly (952f344cd 2018-05-18) --- src/bin/miri.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4e0be7bd32..5ae9626f01 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -5,7 +5,7 @@ extern crate miri; extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; extern crate env_logger; extern crate log_settings; extern crate syntax; @@ -18,7 +18,7 @@ use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use syntax::ast; use std::path::PathBuf; @@ -67,7 +67,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &TransCrate, + trans: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, From 04608016ecd042308f2c55d652f67cac9025ae78 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sat, 19 May 2018 14:09:29 +0200 Subject: [PATCH 4/7] trans -> codegen_backend --- src/bin/miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5ae9626f01..8d80135cde 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -67,7 +67,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &CodegenBackend, + codegen_backend: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, @@ -75,7 +75,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option, ofile: &Option, ) -> Compilation { - self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile) + self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) } fn build_controller( &mut self, From 7d953a65f368fb2b60af5c0dc7ce51e3856ca4d6 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 20 May 2018 11:26:40 +0200 Subject: [PATCH 5/7] Rustup to rustc 1.28.0-nightly (a3085756e 2018-05-19) --- src/fn_call.rs | 34 +++++++++++++++++----------------- src/intrinsic.rs | 12 ++++++------ src/lib.rs | 16 ++++++++-------- src/locks.rs | 11 ++++++----- src/operator.rs | 10 +++++----- 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 272c27e402..e7250eca94 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -1,5 +1,5 @@ use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, Align, LayoutOf}; +use rustc::ty::layout::{self, Align, LayoutOf, Size}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; @@ -187,7 +187,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_null(dest, dest_ty)?; } else { let align = self.tcx.data_layout.pointer_align; - let ptr = self.memory.allocate(size, align, Some(MemoryKind::C.into()))?; + let ptr = self.memory.allocate(Size::from_bytes(size), align, Some(MemoryKind::C.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } } @@ -281,7 +281,7 @@ 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 n = self.value_to_primval(args[2])?.to_u64()?; + let n = Size::from_bytes(self.value_to_primval(args[2])?.to_u64()?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -306,11 +306,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; - if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position( + if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) { - let new_ptr = ptr.offset(num - idx as u64 - 1, &self)?; + let new_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)?; @@ -321,11 +321,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; - if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position( + if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.offset(idx as u64, &self)?; + let new_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)?; @@ -381,12 +381,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if let Some((name, value)) = new { // +1 for the null terminator let value_copy = self.memory.allocate( - (value.len() + 1) as u64, + Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), Some(MemoryKind::Env.into()), )?; self.memory.write_bytes(value_copy.into(), &value)?; - let trailing_zero_ptr = value_copy.offset(value.len() as u64, &self)?.into(); + let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); self.memory.write_bytes(trailing_zero_ptr, &[0])?; if let Some(var) = self.machine.env_vars.insert( name.to_owned(), @@ -410,7 +410,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory.read_bytes(buf, n)?; + let buf_cont = self.memory.read_bytes(buf, Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -502,7 +502,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' key_ptr, key_align, PrimVal::Bytes(key), - key_size.bytes(), + key_size, false, )?; @@ -643,7 +643,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, + let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; @@ -657,10 +657,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, + let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; - self.memory.write_repeat(ptr.into(), 0, size)?; + self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_dealloc" => { @@ -675,7 +675,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.memory.deallocate( ptr, - Some((old_size, Align::from_bytes(align, align).unwrap())), + Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), MemoryKind::Rust.into(), )?; } @@ -692,9 +692,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } let new_ptr = self.memory.reallocate( ptr, - old_size, + Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap(), - new_size, + Size::from_bytes(new_size), Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 234d1ee784..30de1c68ca 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,5 +1,5 @@ use rustc::mir; -use rustc::ty::layout::{TyLayout, LayoutOf}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty; use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer}; @@ -35,7 +35,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested let n = u128::max_value(); - let amt = 128 - self.memory.pointer_size() * 8; + let amt = 128 - self.memory.pointer_size().bytes() * 8; self.write_primval(dest, PrimVal::Bytes((n << amt) >> amt), dest_layout.ty)?; }, @@ -225,7 +225,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: elem_align, dest, elem_align, - count * elem_size, + Size::from_bytes(count * elem_size), intrinsic_name.ends_with("_nonoverlapping"), )?; } @@ -332,7 +332,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "likely" | "unlikely" | "forget" => {} "init" => { - let size = dest_layout.size.bytes(); + let size = dest_layout.size; let init = |this: &mut Self, val: Value| { let zero_val = match val { Value::ByRef(ptr, _) => { @@ -631,7 +631,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "uninit" => { - let size = dest_layout.size.bytes(); + let size = dest_layout.size; let uninit = |this: &mut Self, val: Value| match val { Value::ByRef(ptr, _) => { this.memory.mark_definedness(ptr, size, false)?; @@ -662,7 +662,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // HashMap relies on write_bytes on a NULL ptr with count == 0 to work // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic) self.memory.check_align(ptr, ty_layout.align)?; - self.memory.write_repeat(ptr, val_byte, ty_layout.size.bytes() * count)?; + self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?; } } diff --git a/src/lib.rs b/src/lib.rs index dce31c4ed3..66ad6377e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ extern crate regex; extern crate lazy_static; use rustc::ty::{self, TyCtxt}; -use rustc::ty::layout::{TyLayout, LayoutOf}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty::subst::Subst; use rustc::hir::def_id::DefId; use rustc::mir; @@ -93,7 +93,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } // Return value - let size = ecx.tcx.data_layout.pointer_size.bytes(); + let size = ecx.tcx.data_layout.pointer_size; let align = ecx.tcx.data_layout.pointer_align; let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; cleanup_ptr = Some(ret_ptr); @@ -299,7 +299,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ptr = ecx.memory.allocate( - layout.size.bytes(), + layout.size, layout.align, None, )?; @@ -373,8 +373,8 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Bytes(match layout.size.bytes() { - 0 => 1, - size => size, + 0 => 1 as u128, + size => size as u128, }.into())), ty: usize, }, @@ -407,10 +407,10 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn check_locks<'a>( mem: &Memory<'a, 'mir, 'tcx, Self>, ptr: MemoryPointer, - size: u64, + size: Size, access: AccessKind, ) -> EvalResult<'tcx> { - mem.check_locks(ptr, size, access) + mem.check_locks(ptr, size.bytes(), access) } fn add_lock<'a>( @@ -439,7 +439,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { //ptr, FIXME ptr: MemoryPointer { alloc_id: AllocId(0), - offset: 0, + offset: Size::from_bytes(0), }, lock: lock.active, }.into() diff --git a/src/locks.rs b/src/locks.rs index 677b0454a5..9efbabc717 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -1,5 +1,6 @@ use super::*; use rustc::middle::region; +use rustc::ty::layout::Size; //////////////////////////////////////////////////////////////////////////////// // Locks @@ -116,7 +117,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; let frame = self.cur_frame; locks - .check(Some(frame), ptr.offset, len, access) + .check(Some(frame), ptr.offset.bytes(), len, access) .map_err(|lock| { EvalErrorKind::MemoryLockViolation { ptr, @@ -146,7 +147,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu len, region ); - self.check_bounds(ptr.offset(len, &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) + self.check_bounds(ptr.offset(Size::from_bytes(len), &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) let locks = match self.data.locks.get_mut(&ptr.alloc_id) { Some(locks) => locks, @@ -157,7 +158,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu // Iterate over our range and acquire the lock. If the range is already split into pieces, // we have to manipulate all of them. let lifetime = DynamicLifetime { frame, region }; - for lock in locks.iter_mut(ptr.offset, len) { + for lock in locks.iter_mut(ptr.offset.bytes(), len) { if !lock.access_permitted(None, kind) { return err!(MemoryAcquireConflict { ptr, @@ -203,7 +204,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu None => return Ok(()), }; - 'locks: for lock in locks.iter_mut(ptr.offset, len) { + 'locks: for lock in locks.iter_mut(ptr.offset.bytes(), len) { let is_our_lock = match lock.active { WriteLock(lft) => // Double-check that we are holding the lock. @@ -281,7 +282,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu None => return Ok(()), }; - for lock in locks.iter_mut(ptr.offset, len) { + for lock in locks.iter_mut(ptr.offset.bytes(), len) { // Check if we have a suspension here let (got_the_lock, remove_suspension) = match lock.suspended.get_mut(&lock_id) { None => { diff --git a/src/operator.rs b/src/operator.rs index 220f8f9acd..557e07975d 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -89,9 +89,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Sub => { return self.binary_op( Sub, - PrimVal::Bytes(left.offset as u128), + PrimVal::Bytes(left.offset.bytes() as u128), self.tcx.types.usize, - PrimVal::Bytes(right.offset as u128), + PrimVal::Bytes(right.offset.bytes() as u128), self.tcx.types.usize, ).map(Some) } @@ -150,17 +150,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Add if signed => map_to_primval(left.overflowing_signed_offset(right, self)), Add if !signed => - map_to_primval(left.overflowing_offset(right as u64, self)), + map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1); let right = right as u64; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there - (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, left.offset & right)), false) + (PrimVal::Ptr(MemoryPointer::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 - (PrimVal::from_u128((left.offset & right) as u128), false) + (PrimVal::from_u128((left.offset.bytes() & right) as u128), false) } else { return err!(ReadPointerAsBytes); } From 850841e9ed18b111f9574224d28f7643c1b037c2 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 25 May 2018 14:37:12 +0200 Subject: [PATCH 6/7] s/allocate_cached/allocate_bytes --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 66ad6377e3..f8119245b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,7 +131,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // 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_cached(b"foo\0"); + 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, None)?; From 49ca1746482e3c8221d8e8c7161b7d92ae076c8f Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 26 May 2018 17:07:34 +0200 Subject: [PATCH 7/7] Partial rustup --- benches/helpers/miri_helper.rs | 9 +- src/fn_call.rs | 114 +++++++++--------- src/helpers.rs | 34 +++--- src/intrinsic.rs | 206 +++++++++++++++++---------------- src/lib.rs | 104 ++++++++++++++--- src/locks.rs | 16 +-- src/operator.rs | 101 +++++++++------- src/tls.rs | 24 ++-- src/validation.rs | 6 +- 9 files changed, 358 insertions(+), 256 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 6657ba1199..2bf78b0a71 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -55,16 +55,13 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls<'a> { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); - let (entry_node_id, _) = state.session.entry_fn.borrow().expect( + let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect( "no main or start function found", ); - let entry_def_id = tcx.map.local_def_id(entry_node_id); + let entry_def_id = tcx.hir.local_def_id(entry_node_id); - let memory_size = 100 * 1024 * 1024; // 100MB - let step_limit = 1000_000; - let stack_limit = 100; bencher.borrow_mut().iter(|| { - eval_main(tcx, entry_def_id, memory_size, step_limit, stack_limit); + eval_main(tcx, entry_def_id, None); }); state.session.abort_if_errors(); diff --git a/src/fn_call.rs b/src/fn_call.rs index e7250eca94..ea0c5eb8b2 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -38,7 +38,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_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?; + ecx.write_scalar(discr_dest, Scalar::from_u128(discr_val), discr.ty)?; } layout::Variants::NicheFilling { dataful_variant, @@ -51,7 +51,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_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?; + ecx.write_scalar(niche_dest, Scalar::from_u128(niche_value), niche.ty)?; } } } @@ -182,13 +182,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &link_name[..] { "malloc" => { - let size = self.value_to_primval(args[0])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; if size == 0 { self.write_null(dest, dest_ty)?; } else { let align = self.tcx.data_layout.pointer_align; let ptr = self.memory.allocate(Size::from_bytes(size), align, Some(MemoryKind::C.into()))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } } @@ -209,7 +209,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.value_to_primval(args[0])?.to_u64()? { + match self.value_to_scalar(args[0])?.to_u64()? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -281,7 +281,7 @@ 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 n = Size::from_bytes(self.value_to_primval(args[2])?.to_u64()?); + let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_u64()?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -295,22 +295,22 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } }; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(result as u128), + Scalar::from_i8(result), dest_ty, )?; } "memrchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_primval(args[1])?.to_u64()? as u8; - let num = self.value_to_primval(args[2])?.to_u64()?; + let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) { - let new_ptr = ptr.offset(Size::from_bytes(num - idx as u64 - 1), &self)?; + 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)?; @@ -319,13 +319,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_primval(args[1])?.to_u64()? as u8; - let num = self.value_to_primval(args[2])?.to_u64()?; + let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.offset(Size::from_bytes(idx as u64), &self)?; + 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)?; @@ -337,11 +337,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let name_ptr = self.into_ptr(args[0].value)?.to_ptr()?; let name = self.memory.read_c_str(name_ptr)?; match self.machine.env_vars.get(name) { - Some(&var) => PrimVal::Ptr(var), - None => PrimVal::Bytes(0), + Some(&var) => Scalar::Ptr(var), + None => Scalar::null(), } }; - self.write_primval(dest, result, dest_ty)?; + self.write_scalar(dest, result, dest_ty)?; } "unsetenv" => { @@ -361,7 +361,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.write_null(dest, dest_ty)?; } else { - self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; } } @@ -397,14 +397,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.write_null(dest, dest_ty)?; } else { - self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; } } "write" => { - let fd = self.value_to_primval(args[0])?.to_u64()?; + let fd = self.value_to_scalar(args[0])?.to_u64()?; let buf = self.into_ptr(args[1].value)?; - let n = self.value_to_primval(args[2])?.to_u64()?; + let n = self.value_to_scalar(args[2])?.to_u64()?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -417,16 +417,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' io::stderr().write(buf_cont) }; match res { - Ok(n) => n as isize, + Ok(n) => n as i64, Err(_) => -1, } } else { warn!("Ignored output to FD {}", fd); - n as isize // pretend it all went well + n as i64 // pretend it all went well }; // now result is the value we return back to the program - self.write_primval( + let ptr_size = self.memory.pointer_size(); + self.write_scalar( dest, - PrimVal::Bytes(result as u128), + Scalar::from_isize(result, ptr_size), dest_ty, )?; } @@ -434,22 +435,23 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "strlen" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let n = self.memory.read_c_str(ptr)?.len(); - self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_usize(n as u64, ptr_size), dest_ty)?; } // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?; + self.write_scalar(dest, Scalar::null(), dest_ty)?; } "sysconf" => { - let name = self.value_to_primval(args[0])?.to_u64()?; + let name = self.value_to_scalar(args[0])?.to_u64()?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache let paths = &[ - (&["libc", "_SC_PAGESIZE"], PrimVal::Bytes(4096)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], PrimVal::from_i128(-1)), + (&["libc", "_SC_PAGESIZE"], Scalar::from_i128(4096)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_i128(-1)), ]; let mut result = None; for &(path, path_value) in paths { @@ -467,7 +469,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } if let Some(result) = result { - self.write_primval(dest, result, dest_ty)?; + self.write_scalar(dest, result, dest_ty)?; } else { return err!(Unimplemented( format!("Unimplemented sysconf name: {}", name), @@ -481,11 +483,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let key_align = self.layout_of(args[0].ty)?.align; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match self.into_ptr(args[1].value)?.into_inner_primval() { - PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), - PrimVal::Bytes(0) => None, - PrimVal::Bytes(_) => return err!(ReadBytesAsPointer), - PrimVal::Undef => return err!(ReadUndefBytes), + let dtor = match self.into_ptr(args[1].value)? { + 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 { .. } => return err!(ReadBytesAsPointer), }; // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. @@ -498,10 +500,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) { return err!(OutOfTls); } - self.memory.write_primval( + self.memory.write_scalar( key_ptr, key_align, - PrimVal::Bytes(key), + Scalar::from_u128(key), key_size, false, )?; @@ -511,20 +513,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "pthread_key_delete" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; self.memory.delete_tls_key(key)?; // Return success (0) self.write_null(dest, dest_ty)?; } "pthread_getspecific" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; let ptr = self.memory.load_tls(key)?; self.write_ptr(dest, ptr, dest_ty)?; } "pthread_setspecific" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; let new_ptr = self.into_ptr(args[1].value)?; self.memory.store_tls(key, new_ptr)?; @@ -635,8 +637,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &path[..] { // Allocators are magic. They have no MIR, even when the rest of libstd does. "alloc::alloc::::__rust_alloc" => { - let size = self.value_to_primval(args[0])?.to_u64()?; - let align = self.value_to_primval(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; + let align = self.value_to_scalar(args[1])?.to_u64()?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -646,11 +648,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_alloc_zeroed" => { - let size = self.value_to_primval(args[0])?.to_u64()?; - let align = self.value_to_primval(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; + let align = self.value_to_scalar(args[1])?.to_u64()?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -661,12 +663,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_dealloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_primval(args[1])?.to_u64()?; - let align = self.value_to_primval(args[2])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_u64()?; + let align = self.value_to_scalar(args[2])?.to_u64()?; if old_size == 0 { return err!(HeapAllocZeroBytes); } @@ -681,9 +683,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "alloc::alloc::::__rust_realloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_primval(args[1])?.to_u64()?; - let align = self.value_to_primval(args[2])?.to_u64()?; - let new_size = self.value_to_primval(args[3])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_u64()?; + let align = self.value_to_scalar(args[2])?.to_u64()?; + let new_size = self.value_to_scalar(args[3])?.to_u64()?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } @@ -698,7 +700,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; - self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(new_ptr), dest_ty)?; } // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies). @@ -720,13 +722,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "std::rt::panicking" => { // we abort on panic -> `std::rt::panicking` always returns false let bool = self.tcx.types.bool; - self.write_primval(dest, PrimVal::from_bool(false), bool)?; + self.write_scalar(dest, Scalar::from_bool(false), bool)?; } "std::sys::imp::c::::AddVectoredExceptionHandler" | "std::sys::imp::c::::SetThreadStackGuarantee" => { let usize = self.tcx.types.usize; // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_primval(dest, PrimVal::Bytes(1), usize)?; + self.write_scalar(dest, Scalar::from_u128(1), usize)?; }, _ => return err!(NoMirFor(path)), } @@ -740,6 +742,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { - self.write_primval(dest, PrimVal::Bytes(0), dest_ty) + self.write_scalar(dest, Scalar::null(), dest_ty) } } diff --git a/src/helpers.rs b/src/helpers.rs index a7b94a656d..d881d5c271 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,24 +1,24 @@ use mir; use rustc::ty::Ty; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{LayoutOf, Size}; -use super::{Pointer, EvalResult, PrimVal, EvalContext, ValTy}; +use super::{Scalar, ScalarExt, EvalResult, EvalContext, ValTy}; use rustc_mir::interpret::sign_extend; pub trait EvalContextExt<'tcx> { fn wrapping_pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer>; + ) -> EvalResult<'tcx, Scalar>; fn pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer>; + ) -> EvalResult<'tcx, Scalar>; fn value_to_isize( &self, @@ -44,22 +44,22 @@ pub trait EvalContextExt<'tcx> { impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn wrapping_pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer> { + ) -> EvalResult<'tcx, Scalar> { // 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.wrapping_signed_offset(offset, self) + ptr.ptr_wrapping_signed_offset(offset, self) } fn pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer> { + ) -> EvalResult<'tcx, Scalar> { // This function raises an error if the offset moves the pointer outside of its allocation. We consider // ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0). // We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own @@ -76,9 +76,9 @@ 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; return if let Some(offset) = offset.checked_mul(pointee_size) { - let ptr = ptr.signed_offset(offset, self)?; + let ptr = ptr.ptr_signed_offset(offset, self)?; // Do not do bounds-checking for integers; they can never alias a normal pointer anyway. - if let PrimVal::Ptr(ptr) = ptr.into_inner_primval() { + if let Scalar::Ptr(ptr) = ptr { self.memory.check_bounds(ptr, false)?; } 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. @@ -95,7 +95,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, i64> { assert_eq!(value.ty, self.tcx.types.isize); - let raw = self.value_to_primval(value)?.to_bytes()?; + 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)?; Ok(raw as i64) } @@ -105,7 +105,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, u64> { assert_eq!(value.ty, self.tcx.types.usize); - self.value_to_primval(value)?.to_bytes().map(|v| v as u64) + self.value_to_scalar(value)?.to_bits(self.memory.pointer_size()).map(|v| v as u64) } fn value_to_i32( @@ -113,7 +113,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, i32> { assert_eq!(value.ty, self.tcx.types.i32); - let raw = self.value_to_primval(value)?.to_bytes()?; + 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)?; Ok(raw as i32) } @@ -123,6 +123,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, u8> { assert_eq!(value.ty, self.tcx.types.u8); - self.value_to_primval(value)?.to_bytes().map(|v| v as u8) + self.value_to_scalar(value)?.to_bits(Size::from_bits(8)).map(|v| v as u8) } } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 30de1c68ca..3d537ea629 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,12 +1,14 @@ use rustc::mir; -use rustc::ty::layout::{TyLayout, LayoutOf, Size}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size, Primitive, Integer::*}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer}; +use rustc::mir::interpret::{EvalResult, Scalar, Value}; use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; +use super::ScalarExt; + pub trait EvalContextExt<'tcx> { fn call_intrinsic( &mut self, @@ -36,7 +38,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // alignment bigger than the one requested let n = u128::max_value(); let amt = 128 - self.memory.pointer_size().bytes() * 8; - self.write_primval(dest, PrimVal::Bytes((n << amt) >> amt), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), dest_layout.ty)?; }, "add_with_overflow" => { @@ -77,7 +79,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "assume" => { - let cond = self.value_to_primval(args[0])?.to_bool()?; + let cond = self.value_to_scalar(args[0])?.to_bool()?; if !cond { return err!(AssumptionNotHeld); } @@ -115,16 +117,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let change = self.value_to_primval(args[1])?; + let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), + Value::ScalarPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), }; - self.write_primval(dest, old, ty)?; - self.write_primval( - Place::from_primval_ptr(ptr, align), + self.write_scalar(dest, old, ty)?; + self.write_scalar( + Place::from_scalar_ptr(ptr, align), change, ty, )?; @@ -134,22 +136,22 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let expect_old = self.value_to_primval(args[1])?; - let change = self.value_to_primval(args[2])?; + 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::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), + 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::ByValPair(old, val), + value: Value::ScalarPair(old, val), ty: dest_layout.ty, }; self.write_value(valty, dest)?; - self.write_primval( - Place::from_primval_ptr(ptr, dest_layout.align), + self.write_scalar( + Place::from_scalar_ptr(ptr, dest_layout.align), change, ty, )?; @@ -183,16 +185,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let change = self.value_to_primval(args[1])?; + let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => { + Value::ScalarPair(..) => { bug!("atomic_xadd_relaxed doesn't work with nonprimitives") } }; - self.write_primval(dest, old, ty)?; + self.write_scalar(dest, old, ty)?; let op = match intrinsic_name.split('_').nth(1).unwrap() { "or" => mir::BinOp::BitOr, "xor" => mir::BinOp::BitXor, @@ -203,7 +205,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: }; // FIXME: what do atomics do on overflow? let (val, _) = self.binary_op(op, old, ty, change, ty)?; - self.write_primval(Place::from_primval_ptr(ptr, dest_layout.align), val, ty)?; + self.write_scalar(Place::from_scalar_ptr(ptr, dest_layout.align), val, ty)?; } "breakpoint" => unimplemented!(), // halt miri @@ -233,8 +235,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => { let ty = substs.type_at(0); - let num = self.value_to_primval(args[0])?.to_bytes()?; - let kind = self.ty_to_primval_kind(ty)?; + let num = self.value_to_scalar(args[0])?.to_bytes()?; + let kind = match self.layout_of(ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?, + }; let num = if intrinsic_name.ends_with("_nonzero") { if num == 0 { return err!(Intrinsic(format!("{} called on 0", intrinsic_name))); @@ -243,21 +248,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } else { numeric_intrinsic(intrinsic_name, num, kind)? }; - self.write_primval(dest, num, ty)?; + self.write_scalar(dest, num, ty)?; } "discriminant_value" => { let ty = substs.type_at(0); let adt_ptr = self.into_ptr(args[0].value)?; let adt_align = self.layout_of(args[0].ty)?.align; - let place = Place::from_primval_ptr(adt_ptr, adt_align); + let place = Place::from_scalar_ptr(adt_ptr, adt_align); let discr_val = self.read_discriminant_value(place, ty)?; - self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128(discr_val), dest_layout.ty)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bytes()?; let f = f32::from_bits(f as u32); let f = match intrinsic_name { "sinf32" => f.sin(), @@ -274,12 +279,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf32" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_f32(f), dest_layout.ty)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bytes()?; let f = f64::from_bits(f as u64); let f = match intrinsic_name { "sinf64" => f.sin(), @@ -296,13 +301,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf64" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_f64(f), dest_layout.ty)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { let ty = substs.type_at(0); - let a = self.value_to_primval(args[0])?; - let b = self.value_to_primval(args[1])?; + let a = self.value_to_scalar(args[0])?; + let b = self.value_to_scalar(args[1])?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -312,21 +317,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => bug!(), }; let result = self.binary_op(op, a, ty, b, ty)?; - self.write_primval(dest, result.0, dest_layout.ty)?; + self.write_scalar(dest, result.0, dest_layout.ty)?; } "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` let ty = substs.type_at(0); - let a = self.value_to_primval(args[0])?; - let b = self.value_to_primval(args[1])?; + 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 != PrimVal::Bytes(0) { + if self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0 != Scalar::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)?; - self.write_primval(dest, result.0, dest_layout.ty)?; + self.write_scalar(dest, result.0, dest_layout.ty)?; }, "likely" | "unlikely" | "forget" => {} @@ -341,21 +346,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: val } // TODO(solson): Revisit this, it's fishy to check for Undef here. - Value::ByVal(PrimVal::Undef) => { - match this.ty_to_primval_kind(dest_layout.ty) { - Ok(_) => Value::ByVal(PrimVal::Bytes(0)), - Err(_) => { + 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.ty)?; - let ptr = Pointer::from(PrimVal::Ptr(ptr)); + let ptr = Scalar::Ptr(ptr); this.memory.write_repeat(ptr, 0, size)?; Value::ByRef(ptr, dest_layout.align) } } } - Value::ByVal(_) => Value::ByVal(PrimVal::Bytes(0)), - Value::ByValPair(..) => { - Value::ByValPair(PrimVal::Bytes(0), PrimVal::Bytes(0)) + Value::Scalar(_) => Value::Scalar(Scalar::null()), + Value::ScalarPair(..) => { + Value::ScalarPair(Scalar::null(), Scalar::null()) } }; Ok(zero_val) @@ -376,16 +381,16 @@ 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 = PrimVal::from_u128(elem_align as u128); - self.write_primval(dest, align_val, dest_layout.ty)?; + let align_val = Scalar::from_u128(elem_align as u128); + self.write_scalar(dest, align_val, dest_layout.ty)?; } "pref_align_of" => { let ty = substs.type_at(0); let layout = self.layout_of(ty)?; let align = layout.align.pref(); - let align_val = PrimVal::from_u128(align as u128); - self.write_primval(dest, align_val, dest_layout.ty)?; + let align_val = Scalar::from_u128(align as u128); + self.write_scalar(dest, align_val, dest_layout.ty)?; } "move_val_init" => { @@ -399,9 +404,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let env = ty::ParamEnv::reveal_all(); let needs_drop = ty.needs_drop(self.tcx.tcx, env); - self.write_primval( + self.write_scalar( dest, - PrimVal::from_bool(needs_drop), + Scalar::from_bool(needs_drop), dest_layout.ty, )?; } @@ -444,75 +449,75 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "powf32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); - let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; let f2 = f32::from_bits(f2 as u32); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powf(f2).to_bits() as u128), + Scalar::from_f32(f.powf(f2)), dest_layout.ty, )?; } "powf64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); - let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; let f2 = f64::from_bits(f2 as u64); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powf(f2).to_bits() as u128), + Scalar::from_f64(f.powf(f2)), dest_layout.ty, )?; } "fmaf32" => { - let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let a = f32::from_bits(a as u32); - let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; let b = f32::from_bits(b as u32); - let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(32))?; let c = f32::from_bits(c as u32); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes((a * b + c).to_bits() as u128), + Scalar::from_f32(a * b + c), dest_layout.ty, )?; } "fmaf64" => { - let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let a = f64::from_bits(a as u64); - let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; let b = f64::from_bits(b as u64); - let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(64))?; let c = f64::from_bits(c as u64); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes((a * b + c).to_bits() as u128), + Scalar::from_f64(a * b + c), dest_layout.ty, )?; } "powif32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); let i = self.value_to_i32(args[1])?; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powi(i).to_bits() as u128), + Scalar::from_f32(f.powi(i)), dest_layout.ty, )?; } "powif64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); let i = self.value_to_i32(args[1])?; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powi(i).to_bits() as u128), + Scalar::from_f64(f.powi(i)), dest_layout.ty, )?; } @@ -520,15 +525,15 @@ 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_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128(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)?; - self.write_primval( + self.write_scalar( dest, - PrimVal::from_u128(size.bytes() as u128), + Scalar::from_u128(size.bytes() as u128), dest_layout.ty, )?; } @@ -537,9 +542,9 @@ 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)?; - self.write_primval( + self.write_scalar( dest, - PrimVal::from_u128(align.abi() as u128), + Scalar::from_u128(align.abi() as u128), dest_layout.ty, )?; } @@ -553,7 +558,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_primval(dest, PrimVal::Bytes(n as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::Bits { bits: n as u128, defined: 64 }, dest_layout.ty)?; } "transmute" => { @@ -566,7 +571,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "unchecked_shl" => { let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs >= bits { return err!(Intrinsic( @@ -584,7 +589,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "unchecked_shr" => { let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs >= bits { return err!(Intrinsic( @@ -601,7 +606,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "unchecked_div" => { - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); @@ -616,7 +621,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "unchecked_rem" => { - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); @@ -637,7 +642,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: this.memory.mark_definedness(ptr, size, false)?; Ok(val) } - _ => Ok(Value::ByVal(PrimVal::Undef)), + _ => Ok(Value::Scalar(Scalar::undef())), }; match dest { Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, @@ -681,26 +686,25 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn numeric_intrinsic<'tcx>( name: &str, bytes: u128, - kind: PrimValKind, -) -> EvalResult<'tcx, PrimVal> { + kind: Primitive, +) -> EvalResult<'tcx, Scalar> { macro_rules! integer_intrinsic { ($method:ident) => ({ - use rustc::mir::interpret::PrimValKind::*; let result_bytes = match kind { - I8 => (bytes as i8).$method() as u128, - U8 => (bytes as u8).$method() as u128, - I16 => (bytes as i16).$method() as u128, - U16 => (bytes as u16).$method() as u128, - I32 => (bytes as i32).$method() as u128, - U32 => (bytes as u32).$method() as u128, - I64 => (bytes as i64).$method() as u128, - U64 => (bytes as u64).$method() as u128, - I128 => (bytes as i128).$method() as u128, - U128 => bytes.$method() as u128, + 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, _ => bug!("invalid `{}` argument: {:?}", name, bytes), }; - PrimVal::Bytes(result_bytes) + Scalar::from_u128(result_bytes) }); } diff --git a/src/lib.rs b/src/lib.rs index f8119245b4..e3c83c284d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,81 @@ use validation::EvalContextExt as ValidationEvalContextExt; use range_map::RangeMap; use validation::{ValidationQuery, AbsPlace}; +pub trait ScalarExt { + fn null() -> Self; + fn from_i8(i: i8) -> 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_f32(f: f32) -> Self; + fn from_f64(f: f64) -> Self; + fn to_u64(self) -> EvalResult<'static, u64>; + fn is_null(self) -> EvalResult<'static, bool>; + fn to_bytes(self) -> EvalResult<'static, u128>; +} + +impl ScalarExt for Scalar { + fn null() -> Self { + Scalar::Bits { bits: 0, defined: 128 } + } + + fn from_i8(i: i8) -> Self { + Scalar::Bits { bits: i as i128 as u128, defined: 8 } + } + + fn from_u128(i: u128) -> Self { + Scalar::Bits { bits: i, defined: 128 } + } + + 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_f32(f: f32) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, defined: 32 } + } + + fn from_f64(f: f64) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, defined: 64 } + } + + fn to_u64(self) -> EvalResult<'static, u64> { + let b = self.to_bits(Size::from_bits(64))?; + assert_eq!(b as u64 as u128, b); + Ok(b as u64) + } + + fn is_null(self) -> EvalResult<'static, bool> { + match self { + Scalar::Bits { bits, defined } => { + if defined > 0 { + Ok(bits == 0) + } else { + err!(ReadUndefBytes) + } + } + Scalar::Ptr(_) => Ok(false) + } + } + + fn to_bytes(self) -> EvalResult<'static, u128> { + match self { + Scalar::Bits { defined: 0, .. } => err!(ReadUndefBytes), + Scalar::Bits { bits, .. } => Ok(bits), + Scalar::Ptr(_) => err!(ReadPointerAsBytes), + } + } +} + pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, @@ -65,7 +140,7 @@ pub fn eval_main<'a, 'tcx: 'a>( ) -> EvalResult<'tcx> { let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; - let mut cleanup_ptr = None; // Pointer to be deallocated when we are done + let mut cleanup_ptr = None; // Scalar to be deallocated when we are done if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { return err!(Unimplemented( @@ -116,7 +191,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx)); ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Ptr(main_ptr)), + value: Value::Scalar(Scalar::Ptr(main_ptr)), ty: main_ptr_ty, }, dest, @@ -125,7 +200,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Second argument (argc): 1 let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.types.isize; - ecx.write_primval(dest, PrimVal::Bytes(1), ty)?; + ecx.write_scalar(dest, Scalar::from_u128(1), ty)?; // FIXME: extract main source file path // Third argument (argv): &[b"foo"] @@ -135,7 +210,7 @@ pub fn eval_main<'a, 'tcx: 'a>( 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, None)?; - ecx.memory.write_primval(foo_ptr.into(), ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; + ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?; ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -145,7 +220,7 @@ pub fn eval_main<'a, 'tcx: 'a>( main_instance, main_mir.span, main_mir, - Place::from_primval_ptr(PrimVal::Bytes(1).into(), ty::layout::Align::from_bytes(1, 1).unwrap()), + Place::from_scalar_ptr(Scalar::from_u128(1), ty::layout::Align::from_bytes(1, 1).unwrap()), StackPopCleanup::None, )?; @@ -187,6 +262,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } } } + ::std::process::exit(1); } } } @@ -195,7 +271,7 @@ pub fn eval_main<'a, 'tcx: 'a>( pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program - pub(crate) env_vars: HashMap, MemoryPointer>, + pub(crate) env_vars: HashMap, Pointer>, /// Places that were suspended by the validation subsystem, and will be recovered later pub(crate) suspended: HashMap>>, @@ -205,7 +281,7 @@ pub type TlsKey = usize; #[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { - data: Pointer, // Will eventually become a map from thread IDs to `Pointer`s, if we ever support more than one thread. + data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. dtor: Option>, } @@ -256,11 +332,11 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn try_ptr_op<'a>( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { + ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { ecx.ptr_op(bin_op, left, left_ty, right, right_ty) } @@ -372,7 +448,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::ByVal(PrimVal::Bytes(match layout.size.bytes() { + value: Value::Scalar(Scalar::from_u128(match layout.size.bytes() { 0 => 1 as u128, size => size as u128, }.into())), @@ -385,7 +461,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::ByVal(PrimVal::Bytes(layout.align.abi().into())), + value: Value::Scalar(Scalar::from_u128(layout.align.abi().into())), ty: usize, }, dest, @@ -406,7 +482,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn check_locks<'a>( mem: &Memory<'a, 'mir, 'tcx, Self>, - ptr: MemoryPointer, + ptr: Pointer, size: Size, access: AccessKind, ) -> EvalResult<'tcx> { @@ -437,7 +513,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { .map_err(|lock| { EvalErrorKind::DeallocatedLockedMemory { //ptr, FIXME - ptr: MemoryPointer { + ptr: Pointer { alloc_id: AllocId(0), offset: Size::from_bytes(0), }, diff --git a/src/locks.rs b/src/locks.rs index 9efbabc717..a463f8ba57 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -70,27 +70,27 @@ impl<'tcx> LockInfo<'tcx> { pub trait MemoryExt<'tcx> { fn check_locks( &self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, access: AccessKind, ) -> EvalResult<'tcx>; fn acquire_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, region: Option, kind: AccessKind, ) -> EvalResult<'tcx>; fn suspend_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, suspend: Option, ) -> EvalResult<'tcx>; fn recover_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, lock_region: Option, @@ -103,7 +103,7 @@ pub trait MemoryExt<'tcx> { impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn check_locks( &self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, access: AccessKind, ) -> EvalResult<'tcx> { @@ -132,7 +132,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// Acquire the lock for the given lifetime fn acquire_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, region: Option, kind: AccessKind, @@ -191,7 +191,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// When suspending, the same cases are fine; we just register an additional suspension. fn suspend_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, suspend: Option, @@ -264,7 +264,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// Release a suspension from the write lock. If this is the last suspension or if there is no suspension, acquire the lock. fn recover_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, lock_region: Option, diff --git a/src/operator.rs b/src/operator.rs index 557e07975d..721b4f0bfd 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,4 +1,5 @@ use rustc::ty; +use rustc::ty::layout::Primitive; use rustc::mir; use super::*; @@ -9,38 +10,58 @@ pub trait EvalContextExt<'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>>; + ) -> EvalResult<'tcx, Option<(Scalar, bool)>>; fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: MemoryPointer, + left: Pointer, right: i128, signed: bool, - ) -> EvalResult<'tcx, (PrimVal, bool)>; + ) -> EvalResult<'tcx, (Scalar, bool)>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn ptr_op( &self, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { - use rustc::mir::interpret::PrimValKind::*; + ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { use rustc::mir::BinOp::*; - let usize = PrimValKind::from_uint_size(self.memory.pointer_size()); - let isize = PrimValKind::from_int_size(self.memory.pointer_size()); - let left_kind = self.ty_to_primval_kind(left_ty)?; - let right_kind = self.ty_to_primval_kind(right_ty)?; + use rustc::ty::layout::Integer::*; + let usize = Primitive::Int(match self.memory.pointer_size().bytes() { + 1 => I8, + 2 => I16, + 4 => I32, + 8 => I64, + 16 => I128, + _ => unreachable!(), + }, false); + let isize = Primitive::Int(match self.memory.pointer_size().bytes() { + 1 => I8, + 2 => I16, + 4 => I32, + 8 => I64, + 16 => I128, + _ => unreachable!(), + }, true); + let left_kind = match self.layout_of(left_ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(EvalErrorKind::TypeNotPrimitive(left_ty))?, + }; + let right_kind = match self.layout_of(right_ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(EvalErrorKind::TypeNotPrimitive(right_ty))?, + }; match bin_op { - Offset if left_kind == Ptr && right_kind == usize => { + Offset if left_kind == Primitive::Pointer && right_kind == usize => { let pointee_ty = left_ty .builtin_deref(true) .expect("Offset called on non-ptr type") @@ -48,35 +69,35 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ptr = self.pointer_offset( left.into(), pointee_ty, - right.to_bytes()? as i64, + right.to_bits(self.memory.pointer_size())? as i64, )?; - Ok(Some((ptr.into_inner_primval(), false))) + Ok(Some((ptr, false))) } // These work on anything Eq if left_kind == right_kind => { let result = match (left, right) { - (PrimVal::Bytes(left), PrimVal::Bytes(right)) => left == right, - (PrimVal::Ptr(left), PrimVal::Ptr(right)) => left == right, - (PrimVal::Undef, _) | - (_, PrimVal::Undef) => return err!(ReadUndefBytes), + (Scalar::Bits { .. }, Scalar::Bits { .. }) => { + left.to_bits(self.memory.pointer_size())? == right.to_bits(self.memory.pointer_size())? + }, + (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right, _ => false, }; - Ok(Some((PrimVal::from_bool(result), false))) + Ok(Some((Scalar::from_bool(result), false))) } Ne if left_kind == right_kind => { let result = match (left, right) { - (PrimVal::Bytes(left), PrimVal::Bytes(right)) => left != right, - (PrimVal::Ptr(left), PrimVal::Ptr(right)) => left != right, - (PrimVal::Undef, _) | - (_, PrimVal::Undef) => return err!(ReadUndefBytes), + (Scalar::Bits { .. }, Scalar::Bits { .. }) => { + left.to_bits(self.memory.pointer_size())? != right.to_bits(self.memory.pointer_size())? + }, + (Scalar::Ptr(left), Scalar::Ptr(right)) => left != right, _ => true, }; - Ok(Some((PrimVal::from_bool(result), false))) + Ok(Some((Scalar::from_bool(result), false))) } // These need both pointers to be in the same allocation Lt | Le | Gt | Ge | Sub if left_kind == right_kind && - (left_kind == Ptr || left_kind == usize || left_kind == isize) && + (left_kind == Primitive::Pointer || left_kind == usize || left_kind == isize) && left.is_ptr() && right.is_ptr() => { let left = left.to_ptr()?; let right = right.to_ptr()?; @@ -89,15 +110,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Sub => { return self.binary_op( Sub, - PrimVal::Bytes(left.offset.bytes() as u128), + Scalar::Bits { bits: left.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, self.tcx.types.usize, - PrimVal::Bytes(right.offset.bytes() as u128), + Scalar::Bits { bits: right.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, self.tcx.types.usize, ).map(Some) } _ => bug!("We already established it has to be one of these operators."), }; - Ok(Some((PrimVal::from_bool(res), false))) + Ok(Some((Scalar::from_bool(res), false))) } else { // Both are pointers, but from different allocations. err!(InvalidPointerMath) @@ -106,23 +127,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // These work if one operand is a pointer, the other an integer Add | BitAnd | Sub if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_ptr() && right.is_bytes() => { + left.is_ptr() && right.is_bits() => { // Cast to i128 is fine as we checked the kind to be ptr-sized self.ptr_int_arithmetic( bin_op, left.to_ptr()?, - right.to_bytes()? as i128, + right.to_bits(self.memory.pointer_size())? as i128, left_kind == isize, ).map(Some) } Add | BitAnd if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_bytes() && right.is_ptr() => { + left.is_bits() && right.is_ptr() => { // This is a commutative operation, just swap the operands self.ptr_int_arithmetic( bin_op, right.to_ptr()?, - left.to_bytes()? as i128, + left.to_bits(self.memory.pointer_size())? as i128, left_kind == isize, ).map(Some) } @@ -133,14 +154,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: MemoryPointer, + left: Pointer, right: i128, signed: bool, - ) -> EvalResult<'tcx, (PrimVal, bool)> { + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; - fn map_to_primval((res, over): (MemoryPointer, bool)) -> (PrimVal, bool) { - (PrimVal::Ptr(res), over) + fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { + (Scalar::Ptr(res), over) } Ok(match bin_op { @@ -157,10 +178,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let right = right as u64; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there - (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) + (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 - (PrimVal::from_u128((left.offset.bytes() & right) as u128), false) + (Scalar::Bits { bits: (left.offset.bytes() & right) as u128, defined: 128 }, false) } else { return err!(ReadPointerAsBytes); } diff --git a/src/tls.rs b/src/tls.rs index e55cbede23..7f49509ef4 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,17 +1,17 @@ use rustc::{ty, mir}; -use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Pointer, Memory, Evaluator, Place, - StackPopCleanup, EvalContext}; +use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Scalar, ScalarExt, Memory, Evaluator, + Place, StackPopCleanup, EvalContext}; pub trait MemoryExt<'tcx> { fn create_tls_key(&mut self, dtor: Option>) -> TlsKey; fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx>; - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer>; - fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx>; + fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar>; + fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx>; fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>>; + ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>>; } pub trait EvalContextExt<'tcx> { @@ -25,7 +25,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu self.data.thread_local.insert( new_key, TlsEntry { - data: Pointer::null(), + data: Scalar::null(), dtor, }, ); @@ -43,7 +43,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; } - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer> { + fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { return match self.data.thread_local.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); @@ -53,7 +53,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; } - fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx> { + fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { return match self.data.thread_local.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); @@ -85,19 +85,21 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>> { + ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>> { use std::collections::Bound::*; + + let thread_local = &mut self.data.thread_local; let start = match key { Some(key) => Excluded(key), None => Unbounded, }; for (&key, &mut TlsEntry { ref mut data, dtor }) in - self.data.thread_local.range_mut((start, Unbounded)) + thread_local.range_mut((start, Unbounded)) { if !data.is_null()? { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); - *data = Pointer::null(); + *data = Scalar::null(); return Ok(ret); } } diff --git a/src/validation.rs b/src/validation.rs index deb1c5d5bc..24ddffee9d 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -12,7 +12,7 @@ use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; use rustc_mir::interpret::HasMemory; -use super::{EvalContext, Place, PlaceExtra, ValTy}; +use super::{EvalContext, Place, PlaceExtra, ValTy, ScalarExt}; use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; use locks::MemoryExt; @@ -119,7 +119,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Index(v) => { let value = self.frame().get_local(v)?; let ty = self.tcx.tcx.types.usize; - let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; + let n = self.value_to_scalar(ValTy { value, ty })?.to_u64()?; Index(n) }, ConstantIndex { offset, min_length, from_end } => @@ -652,7 +652,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' TyBool | TyFloat(_) | TyChar => { if mode.acquiring() { let val = self.read_place(query.place.1)?; - let val = self.value_to_primval(ValTy { value: val, ty: query.ty })?; + let val = self.value_to_scalar(ValTy { value: val, ty: query.ty })?; val.to_bytes()?; // TODO: Check if these are valid bool/float/codepoint/UTF-8 }