diff options
| author | Oliver Schneider <oli-obk@users.noreply.github.com> | 2017-08-29 09:53:34 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-08-29 09:53:34 +0200 |
| commit | b8329da5e88683bf497f5584d2dde2b824cb86b6 (patch) | |
| tree | 23fccdea7ca314b3e83c4873eebe8b2894322d39 | |
| parent | 44a360d8ba3cd77e86fcb510808e2b1c550d4c46 (diff) | |
| parent | 55eaf5eb5e5854f7f7b47e9a990ef17fbc505f14 (diff) | |
| download | rust-b8329da5e88683bf497f5584d2dde2b824cb86b6.tar.gz rust-b8329da5e88683bf497f5584d2dde2b824cb86b6.zip | |
Merge pull request #311 from RalfJung/memory
Memory API refactoring
| -rw-r--r-- | Cargo.lock | 40 | ||||
| -rw-r--r-- | miri/bin/miri.rs | 28 | ||||
| -rw-r--r-- | miri/fn_call.rs | 6 | ||||
| -rw-r--r-- | miri/intrinsic.rs | 4 | ||||
| -rw-r--r-- | rustc_tests/Cargo.lock | 159 | ||||
| -rw-r--r-- | rustc_tests/src/main.rs | 31 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/cast.rs | 1 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/eval_context.rs | 218 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/memory.rs | 309 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/mod.rs | 4 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/step.rs | 26 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/terminator/mod.rs | 109 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/traits.rs | 16 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/validation.rs | 2 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/value.rs | 22 | ||||
| -rw-r--r-- | tests/compile-fail/null_pointer_deref.rs | 2 | ||||
| -rw-r--r-- | tests/compile-fail/wild_pointer_deref.rs | 2 | ||||
| -rw-r--r-- | tests/compiletest.rs | 30 | ||||
| -rw-r--r-- | tests/run-pass-fullmir/integer-ops.rs | 4 |
19 files changed, 466 insertions, 547 deletions
diff --git a/Cargo.lock b/Cargo.lock index 9e41c301087..00ae333b467 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,24 +21,24 @@ dependencies = [ [[package]] name = "backtrace" version = "0.3.2" -source = "git+https://github.com/alexcrichton/backtrace-rs#3d96a9242ed2096984d15d177f4762b699bee6d4" +source = "git+https://github.com/alexcrichton/backtrace-rs#ac8f8d150ad114b735a020c37762426fc7ad18c4" dependencies = [ "backtrace-sys 0.1.12 (git+https://github.com/alexcrichton/backtrace-rs)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" version = "0.1.12" -source = "git+https://github.com/alexcrichton/backtrace-rs#3d96a9242ed2096984d15d177f4762b699bee6d4" +source = "git+https://github.com/alexcrichton/backtrace-rs#ac8f8d150ad114b735a020c37762426fc7ad18c4" dependencies = [ - "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -99,7 +99,7 @@ dependencies = [ [[package]] name = "dtoa" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -113,12 +113,12 @@ dependencies = [ [[package]] name = "gcc" -version = "0.3.51" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "itoa" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -137,7 +137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.28" +version = "0.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -175,7 +175,7 @@ name = "memchr" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -207,7 +207,7 @@ name = "rand" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -230,7 +230,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc-demangle" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -267,8 +267,8 @@ name = "serde_json" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -353,13 +353,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" "checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" -"checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" +"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" -"checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a" -"checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" +"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a" +"checksum itoa 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f74cf6ca1bdbc28496a2b9798ab7fccc2ca5a42cace95bb2b219577216a5fb90" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb7b49972ee23d8aa1026c365a5b440ba08e35075f18c459980c7395c221ec48" +"checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3d382732ea0fbc09790c4899db3255bdea0fc78b54bf234bd18a63bb603915b6" "checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" @@ -370,7 +370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" -"checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" +"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9" "checksum serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cf823e706be268e73e7747b147aa31c8f633ab4ba31f115efb57e5047c3a76dd" diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index 29c47e35570..337a723a40d 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -19,7 +19,11 @@ use rustc::ty::TyCtxt; use syntax::ast::{self, MetaItemKind, NestedMetaItemKind}; use std::path::PathBuf; -struct MiriCompilerCalls(RustcDefaultCalls); +struct MiriCompilerCalls { + default: RustcDefaultCalls, + /// whether we are building for the host + host_target: bool, +} impl<'a> CompilerCalls<'a> for MiriCompilerCalls { fn early_callback( @@ -30,7 +34,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { descriptions: &rustc_errors::registry::Registry, output: ErrorOutputType, ) -> Compilation { - self.0.early_callback( + self.default.early_callback( matches, sopts, cfg, @@ -47,7 +51,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { ofile: &Option<PathBuf>, descriptions: &rustc_errors::registry::Registry, ) -> Option<(Input, Option<PathBuf>)> { - self.0.no_input( + self.default.no_input( matches, sopts, cfg, @@ -64,17 +68,17 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option<PathBuf>, ofile: &Option<PathBuf>, ) -> Compilation { - self.0.late_callback(matches, sess, input, odir, ofile) + self.default.late_callback(matches, sess, input, odir, ofile) } fn build_controller( &mut self, sess: &Session, matches: &getopts::Matches, ) -> CompileController<'a> { - let mut control = self.0.build_controller(sess, matches); + let mut control = self.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); control.after_analysis.callback = Box::new(after_analysis); - if std::env::var("MIRI_HOST_TARGET") != Ok("yes".to_owned()) { + if !self.host_target { // only fully compile targets on the host control.after_analysis.stop = Compilation::Stop; } @@ -254,6 +258,16 @@ fn main() { // for auxilary builds in unit tests args.push("-Zalways-encode-mir".to_owned()); + let mut host_target = false; + args.retain(|arg| if arg == "--miri_host_target" { + host_target = true; + false // remove the flag, rustc doesn't know it + } else { + true + }); - rustc_driver::run_compiler(&args, &mut MiriCompilerCalls(RustcDefaultCalls), None, None); + rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { + default: RustcDefaultCalls, + host_target, + }, None, None); } diff --git a/miri/fn_call.rs b/miri/fn_call.rs index cb7ee73e996..7dc8f54849f 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -421,11 +421,11 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) { return err!(OutOfTls); } - // TODO: Does this need checking for alignment? - self.memory.write_uint( + self.memory.write_primval( key_ptr.to_ptr()?, - key, + PrimVal::Bytes(key), key_size.bytes(), + false, )?; // Return success (0) diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 3e04f859871..8c722a46ae3 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -4,7 +4,7 @@ use rustc::ty::layout::Layout; use rustc::ty::{self, Ty}; use rustc_miri::interpret::{EvalResult, Lvalue, LvalueExtra, PrimVal, PrimValKind, Value, Pointer, - HasMemory, EvalContext, PtrAndAlign, ValTy}; + HasMemory, AccessKind, EvalContext, PtrAndAlign, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; @@ -624,7 +624,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> if count > 0 { // HashMap relies on write_bytes on a NULL ptr with count == 0 to work // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic) - self.memory.check_align(ptr, ty_align)?; + self.memory.check_align(ptr, ty_align, Some(AccessKind::Write))?; self.memory.write_repeat(ptr, val_byte, size * count)?; } } diff --git a/rustc_tests/Cargo.lock b/rustc_tests/Cargo.lock index 2b6e311bf1b..f2ad1c2c3b0 100644 --- a/rustc_tests/Cargo.lock +++ b/rustc_tests/Cargo.lock @@ -14,24 +14,46 @@ dependencies = [ ] [[package]] +name = "backtrace" +version = "0.3.2" +source = "git+https://github.com/alexcrichton/backtrace-rs#ac8f8d150ad114b735a020c37762426fc7ad18c4" +dependencies = [ + "backtrace-sys 0.1.12 (git+https://github.com/alexcrichton/backtrace-rs)", + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.12" +source = "git+https://github.com/alexcrichton/backtrace-rs#ac8f8d150ad114b735a020c37762426fc7ad18c4" +dependencies = [ + "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "byteorder" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "cargo_metadata" -version = "0.2.3" +name = "cfg-if" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] -name = "dtoa" -version = "0.4.1" +name = "dbghelp-sys" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "env_logger" @@ -43,11 +65,20 @@ dependencies = [ ] [[package]] -name = "itoa" -version = "0.3.1" +name = "gcc" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "lazy_static" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -83,7 +114,6 @@ name = "miri" version = "0.1.0" dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -91,16 +121,6 @@ dependencies = [ ] [[package]] -name = "num-traits" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quote" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] name = "regex" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -118,9 +138,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "rustc-demangle" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "rustc_miri" version = "0.1.0" dependencies = [ + "backtrace 0.3.2 (git+https://github.com/alexcrichton/backtrace-rs)", "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -129,59 +155,6 @@ dependencies = [ ] [[package]] -name = "serde" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde_derive" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_derive_internals" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_json" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synom" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] name = "thread_local" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -191,11 +164,6 @@ dependencies = [ ] [[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] name = "unreachable" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -213,30 +181,37 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" +"checksum backtrace 0.3.2 (git+https://github.com/alexcrichton/backtrace-rs)" = "<none>" +"checksum backtrace-sys 0.1.12 (git+https://github.com/alexcrichton/backtrace-rs)" = "<none>" "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" -"checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" -"checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" +"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" -"checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" +"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" "checksum libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb7b49972ee23d8aa1026c365a5b440ba08e35075f18c459980c7395c221ec48" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3d382732ea0fbc09790c4899db3255bdea0fc78b54bf234bd18a63bb603915b6" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" -"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" -"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" -"checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9" -"checksum serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cf823e706be268e73e7747b147aa31c8f633ab4ba31f115efb57e5047c3a76dd" -"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a" -"checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b" -"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 4cff381b332..ea699833f6f 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -20,7 +20,11 @@ use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; use syntax::ast; -struct MiriCompilerCalls(RustcDefaultCalls); +struct MiriCompilerCalls { + default: RustcDefaultCalls, + /// whether we are building for the host + host_target: bool, +} impl<'a> CompilerCalls<'a> for MiriCompilerCalls { fn early_callback( @@ -31,7 +35,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { descriptions: &rustc_errors::registry::Registry, output: ErrorOutputType ) -> Compilation { - self.0.early_callback(matches, sopts, cfg, descriptions, output) + self.default.early_callback(matches, sopts, cfg, descriptions, output) } fn no_input( &mut self, @@ -42,7 +46,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { ofile: &Option<PathBuf>, descriptions: &rustc_errors::registry::Registry ) -> Option<(Input, Option<PathBuf>)> { - self.0.no_input(matches, sopts, cfg, odir, ofile, descriptions) + self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions) } fn late_callback( &mut self, @@ -52,13 +56,13 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option<PathBuf>, ofile: &Option<PathBuf> ) -> Compilation { - self.0.late_callback(matches, sess, input, odir, ofile) + self.default.late_callback(matches, sess, input, odir, ofile) } fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> { - let mut control = self.0.build_controller(sess, matches); + let mut control = self.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); control.after_analysis.callback = Box::new(after_analysis); - if std::env::var("MIRI_HOST_TARGET") != Ok("yes".to_owned()) { + if !self.host_target { // only fully compile targets on the host control.after_analysis.stop = Compilation::Stop; } @@ -139,7 +143,15 @@ fn main() { } let stderr = std::io::stderr(); write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap(); - let mut args: Vec<String> = std::env::args().collect(); + let mut host_target = false; + let mut args: Vec<String> = std::env::args().filter(|arg| { + if arg == "--miri_host_target" { + host_target = true; + false // remove the flag, rustc doesn't know it + } else { + true + } + }).collect(); // file to process args.push(path.display().to_string()); @@ -168,7 +180,10 @@ fn main() { let buf = BufWriter::default(); let output = buf.clone(); let result = std::panic::catch_unwind(|| { - rustc_driver::run_compiler(&args, &mut MiriCompilerCalls(RustcDefaultCalls), None, Some(Box::new(buf))); + rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { + default: RustcDefaultCalls, + host_target, + }, None, Some(Box::new(buf))); }); match result { diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index c6016509d23..2f45347d113 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -10,6 +10,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { src_ty: Ty<'tcx>, dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx, PrimVal> { + trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty); let src_kind = self.ty_to_primval_kind(src_ty)?; match val { diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 3e00b8a6fbc..044f37947d3 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -578,12 +578,13 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { discr_val: u128, variant_idx: usize, discr_size: u64, + discr_signed: bool, ) -> EvalResult<'tcx> { // FIXME(solson) let dest_ptr = self.force_allocation(dest)?.to_ptr()?; let discr_dest = dest_ptr.offset(discr_offset, &self)?; - self.memory.write_uint(discr_dest, discr_val, discr_size)?; + self.memory.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr_size, discr_signed)?; let dest = Lvalue::Ptr { ptr: PtrAndAlign { @@ -723,6 +724,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { discr_val, variant, discr_size, + false, )?; } else { bug!("tried to assign {:?} to Layout::General", kind); @@ -765,24 +767,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let operand_ty = self.operand_ty(operand); assert_eq!(self.type_size(operand_ty)?, Some(0)); } - let (offset, TyAndPacked { ty, packed: _ }) = - self.nonnull_offset_and_ty( - dest_ty, - nndiscr, - discrfield_source, - )?; - // TODO: The packed flag is ignored - - // FIXME(solson) - let dest = self.force_allocation(dest)?.to_ptr()?; - - let dest = dest.offset(offset.bytes(), &self)?; - let dest_size = self.type_size(ty)?.expect( - "bad StructWrappedNullablePointer discrfield", - ); - self.memory.write_maybe_aligned_mut( - !nonnull.packed, - |mem| mem.write_int(dest, 0, dest_size), + self.write_struct_wrapped_null_pointer( + dest_ty, + nndiscr, + discrfield_source, + dest, )?; } } else { @@ -997,16 +986,17 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let ptr = self.force_allocation(lval)?.to_ptr()?; let discr_val = self.read_discriminant_value(ptr, ty)?; if let ty::TyAdt(adt_def, _) = ty.sty { + trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(self.tcx).collect::<Vec<_>>()); if adt_def.discriminants(self.tcx).all(|v| { discr_val != v.to_u128_unchecked() }) { return err!(InvalidDiscriminant); } + self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?; } else { bug!("rustc only generates Rvalue::Discriminant for enums"); } - self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?; } } @@ -1017,6 +1007,33 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Ok(()) } + pub(crate) fn write_struct_wrapped_null_pointer( + &mut self, + dest_ty: ty::Ty<'tcx>, + nndiscr: u64, + discrfield_source: &layout::FieldPath, + dest: Lvalue, + ) -> EvalResult<'tcx> { + let (offset, TyAndPacked { ty, packed }) = self.nonnull_offset_and_ty( + dest_ty, + nndiscr, + discrfield_source, + )?; + let nonnull = self.force_allocation(dest)?.to_ptr()?.offset( + offset.bytes(), + &self, + )?; + trace!("struct wrapped nullable pointer type: {}", ty); + // only the pointer part of a fat pointer is used for this space optimization + let discr_size = self.type_size(ty)?.expect( + "bad StructWrappedNullablePointer discrfield", + ); + self.memory.write_maybe_aligned_mut(!packed, |mem| { + // We're writing 0, signedness does not matter + mem.write_primval(nonnull, PrimVal::Bytes(0), discr_size, false) + }) + } + pub(super) fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool { match ty.sty { ty::TyRawPtr(ref tam) | @@ -1294,6 +1311,96 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } } + pub fn read_discriminant_value( + &self, + adt_ptr: MemoryPointer, + adt_ty: Ty<'tcx>, + ) -> EvalResult<'tcx, u128> { + use rustc::ty::layout::Layout::*; + let adt_layout = self.type_layout(adt_ty)?; + //trace!("read_discriminant_value {:#?}", adt_layout); + + let discr_val = match *adt_layout { + General { discr, .. } => { + let discr_size = discr.size().bytes(); + self.memory.read_primval(adt_ptr, discr_size, false)?.to_bytes()? + } + + CEnum { + discr, + signed, + .. + } => { + let discr_size = discr.size().bytes(); + self.memory.read_primval(adt_ptr, discr_size, signed)?.to_bytes()? + } + + RawNullablePointer { nndiscr, value } => { + let discr_size = value.size(&self.tcx.data_layout).bytes(); + trace!("rawnullablepointer with size {}", discr_size); + self.read_nonnull_discriminant_value( + adt_ptr, + nndiscr as u128, + discr_size, + )? + } + + StructWrappedNullablePointer { + nndiscr, + ref discrfield_source, + .. + } => { + let (offset, TyAndPacked { ty, packed }) = self.nonnull_offset_and_ty( + adt_ty, + nndiscr, + discrfield_source, + )?; + let nonnull = adt_ptr.offset(offset.bytes(), &*self)?; + trace!("struct wrapped nullable pointer type: {}", ty); + // only the pointer part of a fat pointer is used for this space optimization + let discr_size = self.type_size(ty)?.expect( + "bad StructWrappedNullablePointer discrfield", + ); + self.read_maybe_aligned(!packed, |ectx| { + ectx.read_nonnull_discriminant_value(nonnull, nndiscr as u128, discr_size) + })? + } + + // The discriminant_value intrinsic returns 0 for non-sum types. + Array { .. } | + FatPointer { .. } | + Scalar { .. } | + Univariant { .. } | + Vector { .. } | + UntaggedUnion { .. } => 0, + }; + + Ok(discr_val) + } + + fn read_nonnull_discriminant_value( + &self, + ptr: MemoryPointer, + nndiscr: u128, + discr_size: u64, + ) -> EvalResult<'tcx, u128> { + trace!( + "read_nonnull_discriminant_value: {:?}, {}, {}", + ptr, + nndiscr, + discr_size + ); + // We are only interested in 0 vs. non-0, the sign does not matter for this + let null = match self.memory.read_primval(ptr, discr_size, false)? { + PrimVal::Bytes(0) => true, + PrimVal::Bytes(_) | + PrimVal::Ptr(..) => false, + PrimVal::Undef => return err!(ReadUndefBytes), + }; + assert!(nndiscr == 0 || nndiscr == 1); + Ok(if !null { nndiscr } else { 1 - nndiscr }) + } + pub fn read_global_as_value(&self, gid: GlobalId) -> Value { Value::ByRef(*self.globals.get(&gid).expect("global not cached")) } @@ -1515,7 +1622,13 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } Value::ByVal(primval) => { let size = self.type_size(dest_ty)?.expect("dest type must be sized"); - self.memory.write_primval(dest, primval, size) + if size == 0 { + assert!(primval.is_undef()); + Ok(()) + } else { + // TODO: Do we need signedness? + self.memory.write_primval(dest.to_ptr()?, primval, size, false) + } } Value::ByValPair(a, b) => self.write_pair_to_ptr(a, b, dest.to_ptr()?, dest_ty), } @@ -1553,11 +1666,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { ); let field_0_ptr = ptr.offset(field_0.bytes(), &self)?.into(); let field_1_ptr = ptr.offset(field_1.bytes(), &self)?.into(); + // TODO: What about signedess? self.write_maybe_aligned_mut(!packed, |ectx| { - ectx.memory.write_primval(field_0_ptr, a, field_0_size) + ectx.memory.write_primval(field_0_ptr, a, field_0_size, false) })?; self.write_maybe_aligned_mut(!packed, |ectx| { - ectx.memory.write_primval(field_1_ptr, b, field_1_size) + ectx.memory.write_primval(field_1_ptr, b, field_1_size, false) })?; Ok(()) } @@ -1675,18 +1789,19 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { ptr: MemoryPointer, pointee_ty: Ty<'tcx>, ) -> EvalResult<'tcx, Value> { - let p = self.memory.read_ptr(ptr)?; + let ptr_size = self.memory.pointer_size(); + let p : Pointer = self.memory.read_ptr_sized_unsigned(ptr)?.into(); if self.type_is_sized(pointee_ty) { Ok(p.to_value()) } else { trace!("reading fat pointer extra of type {}", pointee_ty); - let extra = ptr.offset(self.memory.pointer_size(), self)?; + let extra = ptr.offset(ptr_size, self)?; match self.tcx.struct_tail(pointee_ty).sty { ty::TyDynamic(..) => Ok(p.to_value_with_vtable( - self.memory.read_ptr(extra)?.to_ptr()?, + self.memory.read_ptr_sized_unsigned(extra)?.to_ptr()?, )), ty::TySlice(..) | ty::TyStr => Ok( - p.to_value_with_len(self.memory.read_usize(extra)?), + p.to_value_with_len(self.memory.read_ptr_sized_unsigned(extra)?.to_bytes()? as u64), ), _ => bug!("unsized primval ptr read from {:?}", pointee_ty), } @@ -1696,10 +1811,19 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { fn try_read_value(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> { use syntax::ast::FloatTy; + let ptr = ptr.to_ptr()?; let val = match ty.sty { - ty::TyBool => PrimVal::from_bool(self.memory.read_bool(ptr.to_ptr()?)?), + ty::TyBool => { + let val = self.memory.read_primval(ptr, 1, false)?; + let val = match val { + PrimVal::Bytes(0) => false, + PrimVal::Bytes(1) => true, + _ => return err!(InvalidBool), + }; + PrimVal::from_bool(val) + } ty::TyChar => { - let c = self.memory.read_uint(ptr.to_ptr()?, 4)? as u32; + let c = self.memory.read_primval(ptr, 4, false)?.to_bytes()? as u32; match ::std::char::from_u32(c) { Some(ch) => PrimVal::from_char(ch), None => return err!(InvalidChar(c as u128)), @@ -1716,15 +1840,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { I128 => 16, Is => self.memory.pointer_size(), }; - // if we transmute a ptr to an isize, reading it back into a primval shouldn't panic - // Due to read_ptr ignoring the sign, we need to jump around some hoops - match self.memory.read_int(ptr.to_ptr()?, size) { - Err(EvalError { kind: EvalErrorKind::ReadPointerAsBytes, .. }) if size == self.memory.pointer_size() => - // Reading as an int failed because we are seeing ptr bytes *and* we are actually reading at ptr size. - // Let's try again, reading a ptr this time. - self.memory.read_ptr(ptr.to_ptr()?)?.into_inner_primval(), - other => PrimVal::from_i128(other?), - } + self.memory.read_primval(ptr, size, true)? } ty::TyUint(uint_ty) => { @@ -1737,36 +1853,24 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { U128 => 16, Us => self.memory.pointer_size(), }; - // if we transmute a ptr to an usize, reading it back into a primval shouldn't panic - // for consistency's sake, we use the same code as above - match self.memory.read_uint(ptr.to_ptr()?, size) { - Err(EvalError { kind: EvalErrorKind::ReadPointerAsBytes, .. }) - if size == self.memory.pointer_size() => { - self.memory.read_ptr(ptr.to_ptr()?)?.into_inner_primval() - } - other => PrimVal::from_u128(other?), - } + self.memory.read_primval(ptr, size, false)? } - ty::TyFloat(FloatTy::F32) => PrimVal::from_f32(self.memory.read_f32(ptr.to_ptr()?)?), - ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(ptr.to_ptr()?)?), + ty::TyFloat(FloatTy::F32) => PrimVal::Bytes(self.memory.read_primval(ptr, 4, false)?.to_bytes()?), + ty::TyFloat(FloatTy::F64) => PrimVal::Bytes(self.memory.read_primval(ptr, 8, false)?.to_bytes()?), - ty::TyFnPtr(_) => self.memory.read_ptr(ptr.to_ptr()?)?.into_inner_primval(), + ty::TyFnPtr(_) => self.memory.read_ptr_sized_unsigned(ptr)?, ty::TyRef(_, ref tam) | - ty::TyRawPtr(ref tam) => return self.read_ptr(ptr.to_ptr()?, tam.ty).map(Some), + ty::TyRawPtr(ref tam) => return self.read_ptr(ptr, tam.ty).map(Some), ty::TyAdt(def, _) => { if def.is_box() { - return self.read_ptr(ptr.to_ptr()?, ty.boxed_ty()).map(Some); + return self.read_ptr(ptr, ty.boxed_ty()).map(Some); } use rustc::ty::layout::Layout::*; if let CEnum { discr, signed, .. } = *self.type_layout(ty)? { let size = discr.size().bytes(); - if signed { - PrimVal::from_i128(self.memory.read_int(ptr.to_ptr()?, size)?) - } else { - PrimVal::from_u128(self.memory.read_uint(ptr.to_ptr()?, size)?) - } + self.memory.read_primval(ptr, size, signed)? } else { return Ok(None); } diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 34de9596f24..e1a0a7d3659 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -3,7 +3,7 @@ use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque}; use std::{fmt, iter, ptr, mem, io}; use std::cell::Cell; -use rustc::ty; +use rustc::ty::Instance; use rustc::ty::layout::{self, TargetDataLayout, HasDataLayout}; use syntax::ast::Mutability; use rustc::middle::region::CodeExtent; @@ -250,10 +250,10 @@ pub struct Memory<'a, 'tcx, M: Machine<'tcx>> { /// Function "allocations". They exist solely so pointers have something to point to, and /// we can figure out what they point to. - functions: Vec<ty::Instance<'tcx>>, + functions: Vec<Instance<'tcx>>, /// Inverse map of `functions` so we don't allocate a new pointer every time we need one - function_alloc_cache: HashMap<ty::Instance<'tcx>, AllocId>, + function_alloc_cache: HashMap<Instance<'tcx>, AllocId>, /// Target machine data layout to emulate. pub layout: &'a TargetDataLayout, @@ -297,7 +297,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { }) } - pub fn create_fn_alloc(&mut self, instance: ty::Instance<'tcx>) -> MemoryPointer { + pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> MemoryPointer { if let Some(&alloc_id) = self.function_alloc_cache.get(&instance) { return MemoryPointer::new(alloc_id, 0); } @@ -476,27 +476,38 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } /// Check that the pointer is aligned AND non-NULL. - pub fn check_align(&self, ptr: Pointer, align: u64) -> EvalResult<'tcx> { - let offset = match ptr.into_inner_primval() { + pub fn check_align(&self, ptr: Pointer, align: u64, access: Option<AccessKind>) -> EvalResult<'tcx> { + // Check non-NULL/Undef, extract offset + let (offset, alloc_align) = match ptr.into_inner_primval() { PrimVal::Ptr(ptr) => { let alloc = self.get(ptr.alloc_id)?; - if alloc.align < align { - return err!(AlignmentCheckFailed { - has: alloc.align, - required: align, - }); - } - ptr.offset + (ptr.offset, alloc.align) } PrimVal::Bytes(bytes) => { let v = ((bytes as u128) % (1 << self.pointer_size())) as u64; if v == 0 { return err!(InvalidNullPointerUsage); } - v + (v, align) // the base address if the "integer allocation" is 0 and hence always aligned } PrimVal::Undef => return err!(ReadUndefBytes), }; + // See if alignment checking is disabled + let enforce_alignment = match access { + Some(AccessKind::Read) => self.reads_are_aligned.get(), + Some(AccessKind::Write) => self.writes_are_aligned.get(), + None => true, + }; + if !enforce_alignment { + return Ok(()); + } + // Check alignment + if alloc_align < align { + return err!(AlignmentCheckFailed { + has: alloc_align, + required: align, + }); + } if offset % align == 0 { Ok(()) } else { @@ -804,7 +815,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } } - pub fn get_mut(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation<M::MemoryKinds>> { + fn get_mut(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation<M::MemoryKinds>> { let alloc = self.get_mut_unchecked(id)?; if alloc.mutable == Mutability::Mutable { Ok(alloc) @@ -813,7 +824,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } } - pub fn get_fn(&self, ptr: MemoryPointer) -> EvalResult<'tcx, ty::Instance<'tcx>> { + pub fn get_fn(&self, ptr: MemoryPointer) -> EvalResult<'tcx, Instance<'tcx>> { if ptr.offset != 0 { return err!(InvalidFunctionPointer); } @@ -933,9 +944,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { align: u64, ) -> EvalResult<'tcx, &[u8]> { // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL - if self.reads_are_aligned.get() { - self.check_align(ptr.into(), align)?; - } + self.check_align(ptr.into(), align, Some(AccessKind::Read))?; if size == 0 { return Ok(&[]); } @@ -955,9 +964,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { align: u64, ) -> EvalResult<'tcx, &mut [u8]> { // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL - if self.writes_are_aligned.get() { - self.check_align(ptr.into(), align)?; - } + self.check_align(ptr.into(), align, Some(AccessKind::Write))?; if size == 0 { return Ok(&mut []); } @@ -995,7 +1002,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { /// Reading and writing impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { /// mark an allocation pointed to by a static as static and initialized - pub fn mark_inner_allocation( + fn mark_inner_allocation_initialized( &mut self, alloc: AllocId, mutability: Mutability, @@ -1056,7 +1063,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { }; // recurse into inner allocations for &alloc in relocations.values() { - self.mark_inner_allocation(alloc, mutability)?; + self.mark_inner_allocation_initialized(alloc, mutability)?; } // put back the relocations self.alloc_map @@ -1074,14 +1081,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { align: u64, nonoverlapping: bool, ) -> EvalResult<'tcx> { + // Empty accesses don't need to be valid pointers, but they should still be aligned + self.check_align(src, align, Some(AccessKind::Read))?; + self.check_align(dest, align, Some(AccessKind::Write))?; if size == 0 { - // Empty accesses don't need to be valid pointers, but they should still be aligned - if self.reads_are_aligned.get() { - self.check_align(src, align)?; - } - if self.writes_are_aligned.get() { - self.check_align(dest, align)?; - } return Ok(()); } let src = src.to_ptr()?; @@ -1148,22 +1151,18 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } pub fn read_bytes(&self, ptr: Pointer, size: u64) -> EvalResult<'tcx, &[u8]> { + // Empty accesses don't need to be valid pointers, but they should still be non-NULL + self.check_align(ptr, 1, Some(AccessKind::Read))?; if size == 0 { - // Empty accesses don't need to be valid pointers, but they should still be non-NULL - if self.reads_are_aligned.get() { - self.check_align(ptr, 1)?; - } return Ok(&[]); } self.get_bytes(ptr.to_ptr()?, size, 1) } pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<'tcx> { + // Empty accesses don't need to be valid pointers, but they should still be non-NULL + self.check_align(ptr, 1, Some(AccessKind::Write))?; if src.is_empty() { - // Empty accesses don't need to be valid pointers, but they should still be non-NULL - if self.writes_are_aligned.get() { - self.check_align(ptr, 1)?; - } return Ok(()); } let bytes = self.get_bytes_mut(ptr.to_ptr()?, src.len() as u64, 1)?; @@ -1172,11 +1171,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { } pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: u64) -> EvalResult<'tcx> { + // Empty accesses don't need to be valid pointers, but they should still be non-NULL + self.check_align(ptr, 1, Some(AccessKind::Write))?; if count == 0 { - // Empty accesses don't need to be valid pointers, but they should still be non-NULL - if self.writes_are_aligned.get() { - self.check_align(ptr, 1)?; - } return Ok(()); } let bytes = self.get_bytes_mut(ptr.to_ptr()?, count, 1)?; @@ -1186,40 +1183,48 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { Ok(()) } - pub fn read_ptr(&self, ptr: MemoryPointer) -> EvalResult<'tcx, Pointer> { - let size = self.pointer_size(); + pub fn read_primval(&self, ptr: MemoryPointer, size: u64, signed: bool) -> EvalResult<'tcx, PrimVal> { self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer let endianess = self.endianess(); - let bytes = self.get_bytes_unchecked(ptr, size, size)?; + let bytes = self.get_bytes_unchecked(ptr, size, self.int_align(size))?; // Undef check happens *after* we established that the alignment is correct. // We must not return Ok() for unaligned pointers! if self.check_defined(ptr, size).is_err() { return Ok(PrimVal::Undef.into()); } - let offset = read_target_uint(endianess, bytes).unwrap(); - assert_eq!(offset as u64 as u128, offset); - let offset = offset as u64; - let alloc = self.get(ptr.alloc_id)?; - match alloc.relocations.get(&ptr.offset) { - Some(&alloc_id) => Ok(PrimVal::Ptr(MemoryPointer::new(alloc_id, offset)).into()), - None => Ok(PrimVal::Bytes(offset as u128).into()), + // Now we do the actual reading + let bytes = if signed { + read_target_int(endianess, bytes).unwrap() as u128 + } else { + read_target_uint(endianess, bytes).unwrap() + }; + // See if we got a pointer + if size != self.pointer_size() { + if self.relocations(ptr, size)?.count() != 0 { + return err!(ReadPointerAsBytes); + } + } else { + let alloc = self.get(ptr.alloc_id)?; + match alloc.relocations.get(&ptr.offset) { + Some(&alloc_id) => return Ok(PrimVal::Ptr(MemoryPointer::new(alloc_id, bytes as u64))), + None => {}, + } } + // We don't. Just return the bytes. + Ok(PrimVal::Bytes(bytes)) } - pub fn write_ptr(&mut self, dest: MemoryPointer, ptr: MemoryPointer) -> EvalResult<'tcx> { - self.write_usize(dest, ptr.offset as u64)?; - self.get_mut(dest.alloc_id)?.relocations.insert( - dest.offset, - ptr.alloc_id, - ); - Ok(()) + pub fn read_ptr_sized_unsigned(&self, ptr: MemoryPointer) -> EvalResult<'tcx, PrimVal> { + self.read_primval(ptr, self.pointer_size(), false) } - pub fn write_primval(&mut self, dest: Pointer, val: PrimVal, size: u64) -> EvalResult<'tcx> { - match val { - PrimVal::Ptr(ptr) => { + pub fn write_primval(&mut self, ptr: MemoryPointer, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> { + let endianess = self.endianess(); + + let bytes = match val { + PrimVal::Ptr(val) => { assert_eq!(size, self.pointer_size()); - self.write_ptr(dest.to_ptr()?, ptr) + val.offset as u128 } PrimVal::Bytes(bytes) => { @@ -1233,118 +1238,55 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { 16 => !0, n => bug!("unexpected PrimVal::Bytes size: {}", n), }; - self.write_uint(dest.to_ptr()?, bytes & mask, size) + bytes & mask } - PrimVal::Undef => self.mark_definedness(dest, size, false), - } - } + PrimVal::Undef => { + self.mark_definedness(PrimVal::Ptr(ptr).into(), size, false)?; + return Ok(()); + } + }; - pub fn read_bool(&self, ptr: MemoryPointer) -> EvalResult<'tcx, bool> { - let bytes = self.get_bytes(ptr, 1, self.layout.i1_align.abi())?; - match bytes[0] { - 0 => Ok(false), - 1 => Ok(true), - _ => err!(InvalidBool), + { + let align = self.int_align(size); + let dst = self.get_bytes_mut(ptr, size, align)?; + if signed { + write_target_int(endianess, dst, bytes as i128).unwrap(); + } else { + write_target_uint(endianess, dst, bytes).unwrap(); + } } - } - - pub fn write_bool(&mut self, ptr: MemoryPointer, b: bool) -> EvalResult<'tcx> { - let align = self.layout.i1_align.abi(); - self.get_bytes_mut(ptr, 1, align).map( - |bytes| bytes[0] = b as u8, - ) - } - fn int_align(&self, size: u64) -> EvalResult<'tcx, u64> { - match size { - 1 => Ok(self.layout.i8_align.abi()), - 2 => Ok(self.layout.i16_align.abi()), - 4 => Ok(self.layout.i32_align.abi()), - 8 => Ok(self.layout.i64_align.abi()), - 16 => Ok(self.layout.i128_align.abi()), - _ => bug!("bad integer size: {}", size), + // See if we have to also write a relocation + match val { + PrimVal::Ptr(val) => { + self.get_mut(ptr.alloc_id)?.relocations.insert( + ptr.offset, + val.alloc_id, + ); + } + _ => {} } - } - - pub fn read_int(&self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx, i128> { - let align = self.int_align(size)?; - self.get_bytes(ptr, size, align).map(|b| { - read_target_int(self.endianess(), b).unwrap() - }) - } - - pub fn write_int(&mut self, ptr: MemoryPointer, n: i128, size: u64) -> EvalResult<'tcx> { - let align = self.int_align(size)?; - let endianess = self.endianess(); - let b = self.get_bytes_mut(ptr, size, align)?; - write_target_int(endianess, b, n).unwrap(); - Ok(()) - } - - pub fn read_uint(&self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx, u128> { - let align = self.int_align(size)?; - self.get_bytes(ptr, size, align).map(|b| { - read_target_uint(self.endianess(), b).unwrap() - }) - } - pub fn write_uint(&mut self, ptr: MemoryPointer, n: u128, size: u64) -> EvalResult<'tcx> { - let align = self.int_align(size)?; - let endianess = self.endianess(); - let b = self.get_bytes_mut(ptr, size, align)?; - write_target_uint(endianess, b, n).unwrap(); Ok(()) } - pub fn read_isize(&self, ptr: MemoryPointer) -> EvalResult<'tcx, i64> { - self.read_int(ptr, self.pointer_size()).map(|i| i as i64) - } - - pub fn write_isize(&mut self, ptr: MemoryPointer, n: i64) -> EvalResult<'tcx> { - let size = self.pointer_size(); - self.write_int(ptr, n as i128, size) + pub fn write_ptr_sized_unsigned(&mut self, ptr: MemoryPointer, val: PrimVal) -> EvalResult<'tcx> { + let ptr_size = self.pointer_size(); + self.write_primval(ptr, val, ptr_size, false) } - pub fn read_usize(&self, ptr: MemoryPointer) -> EvalResult<'tcx, u64> { - self.read_uint(ptr, self.pointer_size()).map(|i| i as u64) - } - - pub fn write_usize(&mut self, ptr: MemoryPointer, n: u64) -> EvalResult<'tcx> { - let size = self.pointer_size(); - self.write_uint(ptr, n as u128, size) - } - - pub fn write_f32(&mut self, ptr: MemoryPointer, f: f32) -> EvalResult<'tcx> { - let endianess = self.endianess(); - let align = self.layout.f32_align.abi(); - let b = self.get_bytes_mut(ptr, 4, align)?; - write_target_f32(endianess, b, f).unwrap(); - Ok(()) - } - - pub fn write_f64(&mut self, ptr: MemoryPointer, f: f64) -> EvalResult<'tcx> { - let endianess = self.endianess(); - let align = self.layout.f64_align.abi(); - let b = self.get_bytes_mut(ptr, 8, align)?; - write_target_f64(endianess, b, f).unwrap(); - Ok(()) - } - - pub fn read_f32(&self, ptr: MemoryPointer) -> EvalResult<'tcx, f32> { - self.get_bytes(ptr, 4, self.layout.f32_align.abi()).map( - |b| { - read_target_f32(self.endianess(), b).unwrap() - }, - ) - } - - pub fn read_f64(&self, ptr: MemoryPointer) -> EvalResult<'tcx, f64> { - self.get_bytes(ptr, 8, self.layout.f64_align.abi()).map( - |b| { - read_target_f64(self.endianess(), b).unwrap() - }, - ) + fn int_align(&self, size: u64) -> u64 { + // We assume pointer-sized integers have the same alignment as pointers. + // We also assume signed and unsigned integers of the same size have the same alignment. + match size { + 1 => self.layout.i8_align.abi(), + 2 => self.layout.i16_align.abi(), + 4 => self.layout.i32_align.abi(), + 8 => self.layout.i64_align.abi(), + 16 => self.layout.i128_align.abi(), + _ => bug!("bad integer size: {}", size), + } } } @@ -1493,6 +1435,7 @@ fn read_target_uint(endianess: layout::Endian, mut source: &[u8]) -> Result<u128 layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()), } } + fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result<i128, io::Error> { match endianess { layout::Endian::Little => source.read_int128::<LittleEndian>(source.len()), @@ -1501,44 +1444,6 @@ fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result<i128, } //////////////////////////////////////////////////////////////////////////////// -// Methods to access floats in the target endianess -//////////////////////////////////////////////////////////////////////////////// - -fn write_target_f32( - endianess: layout::Endian, - mut target: &mut [u8], - data: f32, -) -> Result<(), io::Error> { - match endianess { - layout::Endian::Little => target.write_f32::<LittleEndian>(data), - layout::Endian::Big => target.write_f32::<BigEndian>(data), - } -} -fn write_target_f64( - endianess: layout::Endian, - mut target: &mut [u8], - data: f64, -) -> Result<(), io::Error> { - match endianess { - layout::Endian::Little => target.write_f64::<LittleEndian>(data), - layout::Endian::Big => target.write_f64::<BigEndian>(data), - } -} - -fn read_target_f32(endianess: layout::Endian, mut source: &[u8]) -> Result<f32, io::Error> { - match endianess { - layout::Endian::Little => source.read_f32::<LittleEndian>(), - layout::Endian::Big => source.read_f32::<BigEndian>(), - } -} -fn read_target_f64(endianess: layout::Endian, mut source: &[u8]) -> Result<f64, io::Error> { - match endianess { - layout::Endian::Little => source.read_f64::<LittleEndian>(), - layout::Endian::Big => source.read_f64::<BigEndian>(), - } -} - -//////////////////////////////////////////////////////////////////////////////// // Undefined byte tracking //////////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index 603451a9442..9dcb1c9b0f5 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -27,9 +27,9 @@ pub use self::eval_context::{EvalContext, Frame, ResourceLimits, StackPopCleanup pub use self::lvalue::{Lvalue, LvalueExtra, GlobalId}; -pub use self::memory::{AllocId, Memory, MemoryPointer, MemoryKind, HasMemory, AllocIdKind}; +pub use self::memory::{AllocId, Memory, MemoryPointer, MemoryKind, HasMemory, AccessKind, AllocIdKind}; -use self::memory::{PointerArithmetic, Lock, AccessKind}; +use self::memory::{PointerArithmetic, Lock}; use self::range_map::RangeMap; diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index c43ad18e0d8..ea90e39489d 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -11,8 +11,8 @@ use rustc::ty; use rustc::ty::layout::Layout; use rustc::ty::subst::Substs; -use super::{EvalResult, EvalContext, StackPopCleanup, TyAndPacked, PtrAndAlign, GlobalId, Lvalue, - HasMemory, MemoryKind, Machine}; +use super::{EvalResult, EvalContext, StackPopCleanup, PtrAndAlign, GlobalId, Lvalue, + MemoryKind, Machine, PrimVal}; use syntax::codemap::Span; use syntax::ast::Mutability; @@ -106,10 +106,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Layout::General { discr, .. } => { let discr_size = discr.size().bytes(); let dest_ptr = self.force_allocation(dest)?.to_ptr()?; - self.memory.write_uint( + self.memory.write_primval( dest_ptr, - variant_index as u128, + PrimVal::Bytes(variant_index as u128), discr_size, + false )? } @@ -125,23 +126,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { .. } => { if variant_index as u64 != nndiscr { - let (offset, TyAndPacked { ty, packed }) = self.nonnull_offset_and_ty( + self.write_struct_wrapped_null_pointer( dest_ty, nndiscr, discrfield_source, + dest, )?; - let nonnull = self.force_allocation(dest)?.to_ptr()?.offset( - offset.bytes(), - &self, - )?; - trace!("struct wrapped nullable pointer type: {}", ty); - // only the pointer part of a fat pointer is used for this space optimization - let discr_size = self.type_size(ty)?.expect( - "bad StructWrappedNullablePointer discrfield", - ); - self.write_maybe_aligned_mut(!packed, |ectx| { - ectx.memory.write_uint(nonnull, 0, discr_size) - })?; } } @@ -229,7 +219,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { ptr_size, MemoryKind::UninitializedStatic, )?; - self.memory.write_usize(ptr, 0)?; + self.memory.write_ptr_sized_unsigned(ptr, PrimVal::Bytes(0))?; self.memory.mark_static_initalized(ptr.alloc_id, mutability)?; self.globals.insert( cid, diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index af70d9eb846..60893fcec18 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -1,12 +1,11 @@ use rustc::mir; -use rustc::ty::{self, TypeVariants, Ty}; +use rustc::ty::{self, TypeVariants}; use rustc::ty::layout::Layout; use syntax::codemap::Span; use syntax::abi::Abi; -use super::{EvalError, EvalResult, EvalErrorKind, EvalContext, eval_context, TyAndPacked, - PtrAndAlign, Lvalue, MemoryPointer, PrimVal, Value, Machine, HasMemory, ValTy}; -use super::eval_context::IntegerExt; +use super::{EvalResult, EvalContext, eval_context, + PtrAndAlign, Lvalue, PrimVal, Value, Machine, ValTy}; use rustc_data_structures::indexed_vec::Idx; @@ -395,10 +394,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { ty::InstanceDef::Virtual(_, idx) => { let ptr_size = self.memory.pointer_size(); let (ptr, vtable) = args[0].into_ptr_vtable_pair(&self.memory)?; - let fn_ptr = self.memory.read_ptr( - vtable.offset(ptr_size * (idx as u64 + 3), &self)?, - )?; - let instance = self.memory.get_fn(fn_ptr.to_ptr()?)?; + let fn_ptr = self.memory.read_ptr_sized_unsigned( + vtable.offset(ptr_size * (idx as u64 + 3), &self)? + )?.to_ptr()?; + let instance = self.memory.get_fn(fn_ptr)?; let mut args = args.to_vec(); let ty = self.get_field_ty(args[0].ty, 0)?.ty; // TODO: packed flag is ignored args[0].ty = ty; @@ -408,98 +407,4 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } } } - - pub fn read_discriminant_value( - &self, - adt_ptr: MemoryPointer, - adt_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, u128> { - use rustc::ty::layout::Layout::*; - let adt_layout = self.type_layout(adt_ty)?; - //trace!("read_discriminant_value {:#?}", adt_layout); - - let discr_val = match *adt_layout { - General { discr, .. } | - CEnum { - discr, - signed: false, - .. - } => { - let discr_size = discr.size().bytes(); - self.memory.read_uint(adt_ptr, discr_size)? - } - - CEnum { - discr, - signed: true, - .. - } => { - let discr_size = discr.size().bytes(); - self.memory.read_int(adt_ptr, discr_size)? as u128 - } - - RawNullablePointer { nndiscr, value } => { - let discr_size = value.size(&self.tcx.data_layout).bytes(); - trace!("rawnullablepointer with size {}", discr_size); - self.read_nonnull_discriminant_value( - adt_ptr, - nndiscr as u128, - discr_size, - )? - } - - StructWrappedNullablePointer { - nndiscr, - ref discrfield_source, - .. - } => { - let (offset, TyAndPacked { ty, packed }) = self.nonnull_offset_and_ty( - adt_ty, - nndiscr, - discrfield_source, - )?; - let nonnull = adt_ptr.offset(offset.bytes(), &*self)?; - trace!("struct wrapped nullable pointer type: {}", ty); - // only the pointer part of a fat pointer is used for this space optimization - let discr_size = self.type_size(ty)?.expect( - "bad StructWrappedNullablePointer discrfield", - ); - self.read_maybe_aligned(!packed, |ectx| { - ectx.read_nonnull_discriminant_value(nonnull, nndiscr as u128, discr_size) - })? - } - - // The discriminant_value intrinsic returns 0 for non-sum types. - Array { .. } | - FatPointer { .. } | - Scalar { .. } | - Univariant { .. } | - Vector { .. } | - UntaggedUnion { .. } => 0, - }; - - Ok(discr_val) - } - - fn read_nonnull_discriminant_value( - &self, - ptr: MemoryPointer, - nndiscr: u128, - discr_size: u64, - ) -> EvalResult<'tcx, u128> { - trace!( - "read_nonnull_discriminant_value: {:?}, {}, {}", - ptr, - nndiscr, - discr_size - ); - let not_null = match self.memory.read_uint(ptr, discr_size) { - Ok(0) => false, - Ok(_) | - Err(EvalError { kind: EvalErrorKind::ReadPointerAsBytes, .. }) => true, - Err(e) => return Err(e), - }; - assert!(nndiscr == 0 || nndiscr == 1); - Ok(if not_null { nndiscr } else { 1 - nndiscr }) - } } diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 07d7de854b9..3f7e10a9eaf 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -63,19 +63,19 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let drop = eval_context::resolve_drop_in_place(self.tcx, ty); let drop = self.memory.create_fn_alloc(drop); - self.memory.write_ptr(vtable, drop)?; + self.memory.write_ptr_sized_unsigned(vtable, PrimVal::Ptr(drop))?; let size_ptr = vtable.offset(ptr_size, &self)?; - self.memory.write_usize(size_ptr, size)?; + self.memory.write_ptr_sized_unsigned(size_ptr, PrimVal::Bytes(size as u128))?; let align_ptr = vtable.offset(ptr_size * 2, &self)?; - self.memory.write_usize(align_ptr, align)?; + self.memory.write_ptr_sized_unsigned(align_ptr, PrimVal::Bytes(align as u128))?; for (i, method) in ::rustc::traits::get_vtable_methods(self.tcx, trait_ref).enumerate() { if let Some((def_id, substs)) = method { let instance = eval_context::resolve(self.tcx, def_id, substs); let fn_ptr = self.memory.create_fn_alloc(instance); let method_ptr = vtable.offset(ptr_size * (3 + i as u64), &self)?; - self.memory.write_ptr(method_ptr, fn_ptr)?; + self.memory.write_ptr_sized_unsigned(method_ptr, PrimVal::Ptr(fn_ptr))?; } } @@ -105,10 +105,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { vtable: MemoryPointer, ) -> EvalResult<'tcx, (u64, u64)> { let pointer_size = self.memory.pointer_size(); - let size = self.memory.read_usize(vtable.offset(pointer_size, self)?)?; - let align = self.memory.read_usize( - vtable.offset(pointer_size * 2, self)?, - )?; + let size = self.memory.read_ptr_sized_unsigned(vtable.offset(pointer_size, self)?)?.to_bytes()? as u64; + let align = self.memory.read_ptr_sized_unsigned( + vtable.offset(pointer_size * 2, self)? + )?.to_bytes()? as u64; Ok((size, align)) } diff --git a/src/librustc_mir/interpret/validation.rs b/src/librustc_mir/interpret/validation.rs index 20b601b538c..6454e12e037 100644 --- a/src/librustc_mir/interpret/validation.rs +++ b/src/librustc_mir/interpret/validation.rs @@ -275,7 +275,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { // Check alignment and non-NULLness let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?; let ptr = val.into_ptr(&self.memory)?; - self.memory.check_align(ptr, align)?; + self.memory.check_align(ptr, align, None)?; // Recurse let pointee_lvalue = self.val_to_lvalue(val, pointee_ty)?; diff --git a/src/librustc_mir/interpret/value.rs b/src/librustc_mir/interpret/value.rs index 8abb0b86bf8..e052ec1e391 100644 --- a/src/librustc_mir/interpret/value.rs +++ b/src/librustc_mir/interpret/value.rs @@ -176,13 +176,13 @@ impl<'a, 'tcx: 'a> Value { mem: &Memory<'a, 'tcx, M>, ) -> EvalResult<'tcx, Pointer> { use self::Value::*; - match *self { + Ok(match *self { ByRef(PtrAndAlign { ptr, aligned }) => { - mem.read_maybe_aligned(aligned, |mem| mem.read_ptr(ptr.to_ptr()?)) + mem.read_maybe_aligned(aligned, |mem| mem.read_ptr_sized_unsigned(ptr.to_ptr()?))? } ByVal(ptr) | - ByValPair(ptr, _) => Ok(ptr.into()), - } + ByValPair(ptr, _) => ptr, + }.into()) } pub(super) fn into_ptr_vtable_pair<M: Machine<'tcx>>( @@ -196,11 +196,11 @@ impl<'a, 'tcx: 'a> Value { aligned, }) => { mem.read_maybe_aligned(aligned, |mem| { - let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?; - let vtable = mem.read_ptr( + let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?)?.into(); + let vtable = mem.read_ptr_sized_unsigned( ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?, - )?; - Ok((ptr, vtable.to_ptr()?)) + )?.to_ptr()?; + Ok((ptr, vtable)) }) } @@ -222,10 +222,10 @@ impl<'a, 'tcx: 'a> Value { aligned, }) => { mem.read_maybe_aligned(aligned, |mem| { - let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?; - let len = mem.read_usize( + let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?)?.into(); + let len = mem.read_ptr_sized_unsigned( ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?, - )?; + )?.to_bytes()? as u64; Ok((ptr, len)) }) } diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index 20b93aab160..5a26856eba0 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,4 +1,4 @@ fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: a memory access tried to interpret some bytes as a pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: invalid use of NULL pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/wild_pointer_deref.rs b/tests/compile-fail/wild_pointer_deref.rs index 373e308e1c0..57da8dfc01b 100644 --- a/tests/compile-fail/wild_pointer_deref.rs +++ b/tests/compile-fail/wild_pointer_deref.rs @@ -1,5 +1,5 @@ fn main() { - let p = 42 as *const i32; + let p = 44 as *const i32; let x = unsafe { *p }; //~ ERROR: a memory access tried to interpret some bytes as a pointer panic!("this should never print: {}", x); } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 89aa195602e..e7c82367b29 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -126,15 +126,14 @@ fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) { // For now, only validate without optimizations. Inlining breaks validation. flags.push("-Zmir-emit-validate=1".to_owned()); } + if target == host { + flags.push("--miri_host_target".to_owned()); + } config.target_rustcflags = Some(flags.join(" ")); // don't actually execute the final binary, it might be for other targets and we only care // about running miri, not the binary. config.runtool = Some("echo \"\" || ".to_owned()); - if target == host { - std::env::set_var("MIRI_HOST_TARGET", "yes"); - } compiletest::run_tests(&config); - std::env::set_var("MIRI_HOST_TARGET", ""); } fn is_target_dir<P: Into<PathBuf>>(path: P) -> bool { @@ -182,17 +181,24 @@ fn get_host() -> String { String::from(host) } -#[test] -fn run_pass_miri() { +fn run_pass_miri(opt: bool) { let sysroot = get_sysroot(); let host = get_host(); - for &opt in [false, true].iter() { - for_all_targets(&sysroot, |target| { - miri_pass("tests/run-pass", &target, &host, false, opt); - }); - miri_pass("tests/run-pass-fullmir", &host, &host, true, opt); - } + for_all_targets(&sysroot, |target| { + miri_pass("tests/run-pass", &target, &host, false, opt); + }); + miri_pass("tests/run-pass-fullmir", &host, &host, true, opt); +} + +#[test] +fn run_pass_miri_noopt() { + run_pass_miri(false); +} + +#[test] +fn run_pass_miri_opt() { + run_pass_miri(true); } #[test] diff --git a/tests/run-pass-fullmir/integer-ops.rs b/tests/run-pass-fullmir/integer-ops.rs index e761cdd6237..0964b1b32b5 100644 --- a/tests/run-pass-fullmir/integer-ops.rs +++ b/tests/run-pass-fullmir/integer-ops.rs @@ -14,6 +14,10 @@ use std::i32; pub fn main() { + // This tests that do (not) do sign extension properly when loading integers + assert_eq!(u32::max_value() as i64, 4294967295); + assert_eq!(i32::min_value() as i64, -2147483648); + assert_eq!(i8::min_value(), -128); assert_eq!(i8::max_value(), 127); |
