commit
65357faef8
14 changed files with 226 additions and 242 deletions
19
.travis.yml
19
.travis.yml
|
|
@ -1,32 +1,32 @@
|
|||
language: rust
|
||||
cache: cargo
|
||||
|
||||
os:
|
||||
- osx
|
||||
- linux
|
||||
|
||||
rust:
|
||||
- nightly
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
nightly-2018-08-03
|
||||
nightly-2018-08-14
|
||||
|
|
|
|||
8
rustc_tests/Cargo.lock
generated
8
rustc_tests/Cargo.lock
generated
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
extern crate getopts;
|
||||
extern crate miri;
|
||||
extern crate rustc;
|
||||
extern crate rustc_metadata;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_errors;
|
||||
extern crate rustc_codegen_utils;
|
||||
|
|
@ -12,7 +13,7 @@ extern crate syntax;
|
|||
extern crate log;
|
||||
|
||||
use rustc::session::Session;
|
||||
use rustc::middle::cstore::CrateStore;
|
||||
use rustc_metadata::cstore::CStore;
|
||||
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
|
||||
use rustc_driver::driver::{CompileState, CompileController};
|
||||
use rustc::session::config::{self, Input, ErrorOutputType};
|
||||
|
|
@ -70,7 +71,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
|
|||
codegen_backend: &CodegenBackend,
|
||||
matches: &getopts::Matches,
|
||||
sess: &Session,
|
||||
cstore: &CrateStore,
|
||||
cstore: &CStore,
|
||||
input: &Input,
|
||||
odir: &Option<PathBuf>,
|
||||
ofile: &Option<PathBuf>,
|
||||
|
|
|
|||
146
src/fn_call.rs
146
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
149
src/intrinsic.rs
149
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))
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
79
src/lib.rs
79
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<u128>, ptr_size: Size) -> Self;
|
||||
fn from_int(i: impl Into<i128>, ptr_size: Size) -> Self;
|
||||
fn from_f32(f: f32) -> Self;
|
||||
fn from_f64(f: f64) -> Self;
|
||||
fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64>;
|
||||
fn is_null(self) -> EvalResult<'static, bool>;
|
||||
fn is_null(self) -> bool;
|
||||
/// HACK: this function just extracts all bits if `defined != 0`
|
||||
/// Mainly used for args of C-functions and we should totally correctly fetch the size
|
||||
/// of their arguments
|
||||
|
|
@ -73,36 +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<u128>, ptr_size: Size) -> Self {
|
||||
Scalar::Bits { bits: i.into(), size: ptr_size.bytes() as u8 }
|
||||
}
|
||||
|
||||
fn from_i128(i: i128) -> Self {
|
||||
Scalar::Bits { bits: i as u128, defined: 128 }
|
||||
}
|
||||
|
||||
fn from_usize(i: u64, ptr_size: Size) -> Self {
|
||||
Scalar::Bits { bits: i as u128, defined: ptr_size.bits() as u8 }
|
||||
}
|
||||
|
||||
fn from_isize(i: i64, ptr_size: Size) -> Self {
|
||||
Scalar::Bits { bits: i as i128 as u128, defined: ptr_size.bits() as u8 }
|
||||
fn from_int(i: impl Into<i128>, ptr_size: Size) -> Self {
|
||||
Scalar::Bits { bits: i.into() as u128, size: ptr_size.bytes() as u8 }
|
||||
}
|
||||
|
||||
fn from_f32(f: f32) -> Self {
|
||||
Scalar::Bits { bits: f.to_bits() as u128, defined: 32 }
|
||||
Scalar::Bits { bits: f.to_bits() as u128, size: 4 }
|
||||
}
|
||||
|
||||
fn from_f64(f: f64) -> Self {
|
||||
Scalar::Bits { bits: f.to_bits() as u128, defined: 64 }
|
||||
Scalar::Bits { bits: f.to_bits() as u128, size: 8 }
|
||||
}
|
||||
|
||||
fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64> {
|
||||
|
|
@ -111,23 +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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
22
src/tls.rs
22
src/tls.rs
|
|
@ -11,7 +11,7 @@ pub trait MemoryExt<'tcx> {
|
|||
fn fetch_tls_dtor(
|
||||
&mut self,
|
||||
key: Option<TlsKey>,
|
||||
) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>>;
|
||||
) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)>;
|
||||
}
|
||||
|
||||
pub trait EvalContextExt<'tcx> {
|
||||
|
|
@ -22,10 +22,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu
|
|||
fn create_tls_key(&mut self, dtor: Option<ty::Instance<'tcx>>) -> TlsKey {
|
||||
let new_key = self.data.next_thread_local;
|
||||
self.data.next_thread_local += 1;
|
||||
let ptr_size = self.pointer_size();
|
||||
self.data.thread_local.insert(
|
||||
new_key,
|
||||
TlsEntry {
|
||||
data: Scalar::null(),
|
||||
data: Scalar::null(ptr_size).into(),
|
||||
dtor,
|
||||
},
|
||||
);
|
||||
|
|
@ -85,9 +86,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu
|
|||
fn fetch_tls_dtor(
|
||||
&mut self,
|
||||
key: Option<TlsKey>,
|
||||
) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>> {
|
||||
) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> {
|
||||
use std::collections::Bound::*;
|
||||
|
||||
let ptr_size = self.pointer_size();
|
||||
let thread_local = &mut self.data.thread_local;
|
||||
let start = match key {
|
||||
Some(key) => Excluded(key),
|
||||
|
|
@ -96,21 +98,21 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu
|
|||
for (&key, &mut TlsEntry { ref mut data, dtor }) in
|
||||
thread_local.range_mut((start, Unbounded))
|
||||
{
|
||||
if !data.is_null()? {
|
||||
if !data.is_null() {
|
||||
if let Some(dtor) = dtor {
|
||||
let ret = Some((dtor, *data, key));
|
||||
*data = Scalar::null();
|
||||
return Ok(ret);
|
||||
*data = Scalar::null(ptr_size);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>> {
|
||||
fn run_tls_dtors(&mut self) -> EvalResult<'tcx> {
|
||||
let mut dtor = self.memory.fetch_tls_dtor(None)?;
|
||||
let mut dtor = self.memory.fetch_tls_dtor(None);
|
||||
// FIXME: replace loop by some structure that works with stepping
|
||||
while let Some((instance, ptr, key)) = dtor {
|
||||
trace!("Running TLS dtor {:?} on {:?}", instance, ptr);
|
||||
|
|
@ -134,9 +136,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
|
|||
// step until out of stackframes
|
||||
while self.step()? {}
|
||||
|
||||
dtor = match self.memory.fetch_tls_dtor(Some(key))? {
|
||||
dtor = match self.memory.fetch_tls_dtor(Some(key)) {
|
||||
dtor @ Some(_) => dtor,
|
||||
None => self.memory.fetch_tls_dtor(None)?,
|
||||
None => self.memory.fetch_tls_dtor(None),
|
||||
};
|
||||
}
|
||||
// FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`.
|
||||
|
|
|
|||
|
|
@ -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?).
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue