diff --git a/.travis.yml b/.travis.yml index 1be324cba3..7f346b5104 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,32 +1,32 @@ language: rust cache: cargo +rust: +- nightly os: -- osx - linux +- osx -rust: -- nightly before_script: # mac os weirdness (https://github.com/travis-ci/travis-ci/issues/6307) - curl -sSL https://rvm.io/mpapis.asc | gpg --import - - rvm get stable # in a cronjob, use latest (not pinned) nightly - if [ "$TRAVIS_EVENT_TYPE" = cron ]; then rustup override set nightly; fi -# actual travis code +# prepare - export PATH=$HOME/.local/bin:$PATH - rustup target add i686-unknown-linux-gnu - rustup target add i686-pc-windows-gnu - rustup target add i686-pc-windows-msvc - rustup component add rust-src - cargo install xargo || echo "skipping xargo install" -- export RUST_SYSROOT=$HOME/rust + script: - set -e - | # Test and install plain miri cargo build --release --all-features && - RUST_BACKTRACE=1 cargo test --release --all-features --all && + cargo test --release --all-features && cargo install --all-features --force - | # test that the rustc_tests binary compiles @@ -55,7 +55,8 @@ script: cd .. - | # and run all tests with full mir - cargo test --release + cargo test --release --all-features + notifications: email: on_success: never diff --git a/appveyor.yml b/appveyor.yml index 6aee7e75a9..1453241697 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -26,12 +26,12 @@ install: - cd xargo - set RUSTFLAGS=-Zalways-encode-mir -Zmir-emit-validate=1 - xargo build - - set RUSTFLAGS= - cd .. build: false test_script: + - set RUSTFLAGS=-g - set RUST_BACKTRACE=1 - cargo build --release - cargo test --release diff --git a/rust-toolchain b/rust-toolchain index 8e23548106..ec8c56dc62 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-08-03 +nightly-2018-08-14 diff --git a/rustc_tests/Cargo.lock b/rustc_tests/Cargo.lock index 0154ecc2cc..c206ecd644 100644 --- a/rustc_tests/Cargo.lock +++ b/rustc_tests/Cargo.lock @@ -51,11 +51,6 @@ name = "lazy_static" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "lazy_static" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "libc" version = "0.2.30" @@ -91,9 +86,7 @@ version = "0.1.0" dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -226,7 +219,6 @@ dependencies = [ "checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739" "checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 1891e3dba1..969888ec99 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -2,6 +2,7 @@ extern crate miri; extern crate getopts; extern crate rustc; +extern crate rustc_metadata; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_codegen_utils; @@ -14,7 +15,7 @@ use std::io; 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}; @@ -56,7 +57,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { trans: &CodegenBackend, matches: &getopts::Matches, sess: &Session, - cstore: &CrateStore, + cstore: &CStore, input: &Input, odir: &Option, ofile: &Option, diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5889754149..57d49b2e6b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -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, ofile: &Option, diff --git a/src/fn_call.rs b/src/fn_call.rs index 9dfff9f553..509119beb3 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -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,49 +619,51 @@ 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" | "InitializeCriticalSection" | "EnterCriticalSection" | - "TryEnterCriticalSection" | "LeaveCriticalSection" | "DeleteCriticalSection" | "SetLastError" => { + // Function does not return anything, nothing to do + }, + "GetModuleHandleW" | + "GetProcAddress" | + "TryEnterCriticalSection" => { // pretend these do not exist/nothing happened, by returning zero - self.write_scalar(dest, Scalar::from_u128(0), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(0, dest_layout.size), dest_ty)?; }, "GetLastError" => { // this is c::ERROR_CALL_NOT_IMPLEMENTED - self.write_scalar(dest, Scalar::from_u128(120), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(120, dest_layout.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)?; + self.write_scalar(dest, Scalar::from_uint(key, dest_layout.size), dest_layout.ty)?; } "TlsGetValue" => { let key = self.value_to_scalar(args[0])?.to_bytes()?; @@ -664,11 +672,11 @@ 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)?; // Return success (1) - self.write_scalar(dest, Scalar::from_u128(1), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(1, dest_layout.size), dest_ty)?; } // We can't execute anything else @@ -791,7 +799,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) } } diff --git a/src/helpers.rs b/src/helpers.rs index aa699b509f..8482c48460 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -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) } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index dc2224c4ce..cd953ba7c5 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -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,7 @@ 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)?; + self.write_scalar(dest, Scalar::from_uint(discr_val, dest_layout.size), dest_layout.ty)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | @@ -320,7 +320,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 +330,25 @@ 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) - } + // we don't want to force an allocation in case the destination is a simple value + 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,25 @@ 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())), - }; + // we don't want to force an allocation in case the destination is a simple value 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 +647,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 +676,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)) }); } diff --git a/src/lib.rs b/src/lib.rs index f16471352c..705f56d38f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,6 @@ #![feature( rustc_private, catch_expr, - inclusive_range_fields, - inclusive_range_methods, )] #![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] @@ -56,16 +54,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, ptr_size: Size) -> Self; + fn from_int(i: impl Into, 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 +69,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, 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, 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 +99,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 +139,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 +184,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 +193,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 +212,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 +278,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 +503,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 +522,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, diff --git a/src/operator.rs b/src/operator.rs index 207324cfcb..7be77771a7 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -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); } diff --git a/src/tls.rs b/src/tls.rs index ffcf862915..9f0fb2c8f6 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -11,7 +11,7 @@ pub trait MemoryExt<'tcx> { fn fetch_tls_dtor( &mut self, key: Option, - ) -> 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>) -> 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, - ) -> 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`. diff --git a/src/validation.rs b/src/validation.rs index 8d55f8ab0a..7f0abb9ae0 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -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?). } diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat.rs index dad5f4df2d..3e3bf51c3f 100644 --- a/tests/compile-fail/transmute_fat.rs +++ b/tests/compile-fail/transmute_fat.rs @@ -4,12 +4,12 @@ fn main() { #[cfg(target_pointer_width="64")] let bad = unsafe { - std::mem::transmute::<&[u8], u128>(&[1u8]) + std::mem::transmute::<&[u8], [u8; 16]>(&[1u8]) }; #[cfg(target_pointer_width="32")] let bad = unsafe { - std::mem::transmute::<&[u8], u64>(&[1u8]) + std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) }; - let _ = bad + 1; //~ ERROR constant evaluation error + let _ = bad[0] + bad[bad.len()-1]; //~ ERROR constant evaluation error //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes }